kvm-guest-drivers-windows

Форк
0
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; \
40
                      pa = va ? StorPortGetPhysicalAddress(DeviceExtension, NULL, va, &len).QuadPart : 0; \
41
                    }
42

43
VOID
44
SendSRB(
45
    IN PVOID DeviceExtension,
46
    IN PSRB_TYPE Srb
47
    )
48
{
49
    PADAPTER_EXTENSION  adaptExt = (PADAPTER_EXTENSION)DeviceExtension;
50
    PSRB_EXTENSION      srbExt   = NULL;
51
    PVOID               va = NULL;
52
    ULONGLONG           pa = 0;
53
    ULONG               QueueNumber = VIRTIO_SCSI_REQUEST_QUEUE_0;
54
    STOR_LOCK_HANDLE    LockHandle = { 0 };
55
    ULONG               status = STOR_STATUS_SUCCESS;
56
    UCHAR               ScsiStatus = SCSISTAT_GOOD;
57
    ULONG MessageID;
58
    int res = 0;
59
    PREQUEST_LIST       element;
60
    ULONG               index;
61
ENTER_FN_SRB();
62

63
    if (!Srb)
64
        return;
65

66
    if (adaptExt->bRemoved) {
67
        SRB_SET_SRB_STATUS(Srb, SRB_STATUS_NO_DEVICE);
68
        CompleteRequest(DeviceExtension, Srb);
69
        return;
70
    }
71

72
    LOG_SRB_INFO();
73

74
    if (adaptExt->num_queues > 1) {
75
        STARTIO_PERFORMANCE_PARAMETERS param;
76
        param.Size = sizeof(STARTIO_PERFORMANCE_PARAMETERS);
77
        status = StorPortGetStartIoPerfParams(DeviceExtension, (PSCSI_REQUEST_BLOCK)Srb, &param);
78
        if (status == STOR_STATUS_SUCCESS && param.MessageNumber != 0) {
79
            QueueNumber = MESSAGE_TO_QUEUE(param.MessageNumber);
80
            if (QueueNumber >= adaptExt->num_queues + VIRTIO_SCSI_REQUEST_QUEUE_0) {
81
                QueueNumber %= adaptExt->num_queues;
82
            }
83
        } else {
84
            RhelDbgPrint(TRACE_LEVEL_ERROR, " StorPortGetStartIoPerfParams failed srb 0x%p status 0x%x MessageNumber %d.\n", Srb, status, param.MessageNumber);
85
        }
86
    }
87

88
    srbExt = SRB_EXTENSION(Srb);
89

90
    if (!srbExt) {
91
        RhelDbgPrint(TRACE_LEVEL_INFORMATION, " No SRB Extenstion for SRB 0x%p \n", Srb);
92
        return;
93
    }
94

95
    MessageID = QUEUE_TO_MESSAGE(QueueNumber);
96
    index = QueueNumber - VIRTIO_SCSI_REQUEST_QUEUE_0;
97

98
    if (adaptExt->reset_in_progress) {
99
        RhelDbgPrint(TRACE_LEVEL_FATAL, " Reset is in progress, completing SRB 0x%p with SRB_STATUS_BUS_RESET.\n", Srb);
100
        SRB_SET_SRB_STATUS(Srb, SRB_STATUS_BUS_RESET);
101
        CompleteRequest(DeviceExtension, Srb);
102
        return;
103
    }
104

105
    VioScsiVQLock(DeviceExtension, MessageID, &LockHandle, FALSE);
106
    SET_VA_PA();
107
    res = virtqueue_add_buf(adaptExt->vq[QueueNumber],
108
        srbExt->psgl,
109
        srbExt->out, srbExt->in,
110
        &srbExt->cmd, va, pa);
111

112
    if (res >= 0) {
113
        element = &adaptExt->processing_srbs[index];
114
        InsertTailList(&element->srb_list, &srbExt->list_entry);
115
        element->srb_cnt++;
116
    }
117
    VioScsiVQUnlock(DeviceExtension, MessageID, &LockHandle, FALSE);
118
    if ( res >= 0){
119
        if (virtqueue_kick_prepare(adaptExt->vq[QueueNumber])) {
120
            virtqueue_notify(adaptExt->vq[QueueNumber]);
121
        }
122
    } else {
123
        virtqueue_notify(adaptExt->vq[QueueNumber]);
124
        ScsiStatus = SCSISTAT_QUEUE_FULL;
125
        SRB_SET_SRB_STATUS(Srb, SRB_STATUS_BUSY);
126
        SRB_SET_SCSI_STATUS(Srb, ScsiStatus);
127
        StorPortBusy(DeviceExtension, 10);
128
        CompleteRequest(DeviceExtension, Srb);
129
        RhelDbgPrint(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

132
EXIT_FN_SRB();
133
}
134

135
BOOLEAN
136
SynchronizedTMFRoutine(
137
    IN PVOID DeviceExtension,
138
    IN PVOID Context
139
    )
140
{
141
    PADAPTER_EXTENSION  adaptExt = (PADAPTER_EXTENSION)DeviceExtension;
142
    PSCSI_REQUEST_BLOCK Srb      = (PSCSI_REQUEST_BLOCK) Context;
143
    PSRB_EXTENSION      srbExt   = SRB_EXTENSION(Srb);
144
    PVOID               va;
145
    ULONGLONG           pa;
146

147
ENTER_FN();
148
    SET_VA_PA();
149
    if (virtqueue_add_buf(adaptExt->vq[VIRTIO_SCSI_CONTROL_QUEUE],
150
                     srbExt->psgl,
151
                     srbExt->out, srbExt->in,
152
                     &srbExt->cmd, va, pa) >= 0){
153
        virtqueue_kick(adaptExt->vq[VIRTIO_SCSI_CONTROL_QUEUE]);
154
EXIT_FN();
155
        return TRUE;
156
    }
157
    SRB_SET_SRB_STATUS(Srb, SRB_STATUS_BUSY);
158
    StorPortBusy(DeviceExtension, adaptExt->queue_depth);
159
EXIT_ERR();
160
    return FALSE;
161
}
162

163
BOOLEAN
164
SendTMF(
165
    IN PVOID DeviceExtension,
166
    IN PSCSI_REQUEST_BLOCK Srb
167
    )
168
{
169
ENTER_FN();
170
    return StorPortSynchronizeAccess(DeviceExtension, SynchronizedTMFRoutine, (PVOID)Srb);
171
EXIT_FN();
172
}
173

174
BOOLEAN
175
DeviceReset(
176
    IN PVOID DeviceExtension
177
    )
178
{
179
    PADAPTER_EXTENSION adaptExt = (PADAPTER_EXTENSION)DeviceExtension;
180
    PSCSI_REQUEST_BLOCK   Srb = &adaptExt->tmf_cmd.Srb;
181
    PSRB_EXTENSION        srbExt = adaptExt->tmf_cmd.SrbExtension;
182
    VirtIOSCSICmd         *cmd = &srbExt->cmd;
183
    ULONG                 fragLen;
184
    ULONG                 sgElement;
185

186
ENTER_FN();
187
    if (adaptExt->dump_mode) {
188
        return TRUE;
189
    }
190
    ASSERT(adaptExt->tmf_infly == FALSE);
191
    Srb->SrbExtension = srbExt;
192
    RtlZeroMemory((PVOID)cmd, sizeof(VirtIOSCSICmd));
193
    cmd->srb = (PVOID)Srb;
194
    cmd->req.tmf.lun[0] = 1;
195
    cmd->req.tmf.lun[1] = 0;
196
    cmd->req.tmf.lun[2] = 0;
197
    cmd->req.tmf.lun[3] = 0;
198
    cmd->req.tmf.type = VIRTIO_SCSI_T_TMF;
199
    cmd->req.tmf.subtype = VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET;
200

201
    srbExt->psgl = srbExt->vio_sg;
202
    srbExt->pdesc = srbExt->desc_alias;
203
    sgElement = 0;
204
    srbExt->psgl[sgElement].physAddr = StorPortGetPhysicalAddress(DeviceExtension, NULL, &cmd->req.tmf, &fragLen);
205
    srbExt->psgl[sgElement].length   = sizeof(cmd->req.tmf);
206
    sgElement++;
207
    srbExt->out = sgElement;
208
    srbExt->psgl[sgElement].physAddr = StorPortGetPhysicalAddress(DeviceExtension, NULL, &cmd->resp.tmf, &fragLen);
209
    srbExt->psgl[sgElement].length = sizeof(cmd->resp.tmf);
210
    sgElement++;
211
    srbExt->in = sgElement - srbExt->out;
212
    StorPortPause(DeviceExtension, 60);
213
    if (!SendTMF(DeviceExtension, Srb)) {
214
        StorPortResume(DeviceExtension);
215
        return FALSE;
216
    }
217
    adaptExt->tmf_infly = TRUE;
218
    return TRUE;
219
}
220

221
VOID
222
ShutDown(
223
    IN PVOID DeviceExtension
224
    )
225
{
226
    ULONG index;
227
    PADAPTER_EXTENSION adaptExt = (PADAPTER_EXTENSION)DeviceExtension;
228
ENTER_FN();
229
    virtio_device_reset(&adaptExt->vdev);
230
    virtio_delete_queues(&adaptExt->vdev);
231
    for (index = VIRTIO_SCSI_CONTROL_QUEUE; index < adaptExt->num_queues + VIRTIO_SCSI_REQUEST_QUEUE_0; ++index) {
232
        adaptExt->vq[index] = NULL;
233
    }
234

235
    virtio_device_shutdown(&adaptExt->vdev);
236
EXIT_FN();
237
}
238

239
VOID
240
GetScsiConfig(
241
    IN PVOID DeviceExtension
242
)
243
{
244
    PADAPTER_EXTENSION adaptExt = (PADAPTER_EXTENSION)DeviceExtension;
245
ENTER_FN();
246

247
    adaptExt->features = virtio_get_features(&adaptExt->vdev);
248
    adaptExt->indirect = CHECKBIT(adaptExt->features, VIRTIO_RING_F_INDIRECT_DESC);
249

250
    virtio_get_config(&adaptExt->vdev, FIELD_OFFSET(VirtIOSCSIConfig, seg_max),
251
                      &adaptExt->scsi_config.seg_max, sizeof(adaptExt->scsi_config.seg_max));
252
    RhelDbgPrint(TRACE_LEVEL_INFORMATION, " seg_max %lu\n", adaptExt->scsi_config.seg_max);
253

254
    virtio_get_config(&adaptExt->vdev, FIELD_OFFSET(VirtIOSCSIConfig, num_queues),
255
                      &adaptExt->scsi_config.num_queues, sizeof(adaptExt->scsi_config.num_queues));
256
    RhelDbgPrint(TRACE_LEVEL_INFORMATION, " num_queues %lu\n", adaptExt->scsi_config.num_queues);
257

258
    virtio_get_config(&adaptExt->vdev, FIELD_OFFSET(VirtIOSCSIConfig, max_sectors),
259
                      &adaptExt->scsi_config.max_sectors, sizeof(adaptExt->scsi_config.max_sectors));
260
    RhelDbgPrint(TRACE_LEVEL_INFORMATION, " max_sectors %lu\n", adaptExt->scsi_config.max_sectors);
261

262
    virtio_get_config(&adaptExt->vdev, FIELD_OFFSET(VirtIOSCSIConfig, cmd_per_lun),
263
                      &adaptExt->scsi_config.cmd_per_lun, sizeof(adaptExt->scsi_config.cmd_per_lun));
264
    RhelDbgPrint(TRACE_LEVEL_INFORMATION, " cmd_per_lun %lu\n", adaptExt->scsi_config.cmd_per_lun);
265

266
    virtio_get_config(&adaptExt->vdev, FIELD_OFFSET(VirtIOSCSIConfig, event_info_size),
267
                      &adaptExt->scsi_config.event_info_size, sizeof(adaptExt->scsi_config.event_info_size));
268
    RhelDbgPrint(TRACE_LEVEL_INFORMATION, " event_info_size %lu\n", adaptExt->scsi_config.event_info_size);
269

270
    virtio_get_config(&adaptExt->vdev, FIELD_OFFSET(VirtIOSCSIConfig, sense_size),
271
                      &adaptExt->scsi_config.sense_size, sizeof(adaptExt->scsi_config.sense_size));
272
    RhelDbgPrint(TRACE_LEVEL_INFORMATION, " sense_size %lu\n", adaptExt->scsi_config.sense_size);
273

274
    virtio_get_config(&adaptExt->vdev, FIELD_OFFSET(VirtIOSCSIConfig, cdb_size),
275
                      &adaptExt->scsi_config.cdb_size, sizeof(adaptExt->scsi_config.cdb_size));
276
    RhelDbgPrint(TRACE_LEVEL_INFORMATION, " cdb_size %lu\n", adaptExt->scsi_config.cdb_size);
277

278
    virtio_get_config(&adaptExt->vdev, FIELD_OFFSET(VirtIOSCSIConfig, max_channel),
279
                      &adaptExt->scsi_config.max_channel, sizeof(adaptExt->scsi_config.max_channel));
280
    RhelDbgPrint(TRACE_LEVEL_INFORMATION, " max_channel %u\n", adaptExt->scsi_config.max_channel);
281

282
    virtio_get_config(&adaptExt->vdev, FIELD_OFFSET(VirtIOSCSIConfig, max_target),
283
                      &adaptExt->scsi_config.max_target, sizeof(adaptExt->scsi_config.max_target));
284
    RhelDbgPrint(TRACE_LEVEL_INFORMATION, " max_target %u\n", adaptExt->scsi_config.max_target);
285

286
    virtio_get_config(&adaptExt->vdev, FIELD_OFFSET(VirtIOSCSIConfig, max_lun),
287
                      &adaptExt->scsi_config.max_lun, sizeof(adaptExt->scsi_config.max_lun));
288
    RhelDbgPrint(TRACE_LEVEL_INFORMATION, " max_lun %lu\n", adaptExt->scsi_config.max_lun);
289

290
EXIT_FN();
291
}
292

293

294
VOID
295
SetGuestFeatures(
296
    IN PVOID DeviceExtension
297
)
298
{
299
    ULONGLONG          guestFeatures = 0;
300
    PADAPTER_EXTENSION adaptExt = (PADAPTER_EXTENSION)DeviceExtension;
301
ENTER_FN();
302

303
    if (CHECKBIT(adaptExt->features, VIRTIO_F_VERSION_1)) {
304
        guestFeatures |= (1ULL << VIRTIO_F_VERSION_1);
305
        if (CHECKBIT(adaptExt->features, VIRTIO_F_RING_PACKED)) {
306
            guestFeatures |= (1ULL << VIRTIO_F_RING_PACKED);
307
        }
308
    }
309
    if (CHECKBIT(adaptExt->features, VIRTIO_F_ANY_LAYOUT)) {
310
        guestFeatures |= (1ULL << VIRTIO_F_ANY_LAYOUT);
311
    }
312
    if (CHECKBIT(adaptExt->features, VIRTIO_F_ACCESS_PLATFORM)) {
313
        guestFeatures |= (1ULL << VIRTIO_F_ACCESS_PLATFORM);
314
    }
315
    if (CHECKBIT(adaptExt->features, VIRTIO_RING_F_EVENT_IDX)) {
316
        guestFeatures |= (1ULL << VIRTIO_RING_F_EVENT_IDX);
317
    }
318
    if (CHECKBIT(adaptExt->features, VIRTIO_RING_F_INDIRECT_DESC)) {
319
        guestFeatures |= (1ULL << VIRTIO_RING_F_INDIRECT_DESC);
320
    }
321
    if (CHECKBIT(adaptExt->features, VIRTIO_SCSI_F_CHANGE)) {
322
        guestFeatures |= (1ULL << VIRTIO_SCSI_F_CHANGE);
323
    }
324
    if (CHECKBIT(adaptExt->features, VIRTIO_SCSI_F_HOTPLUG)) {
325
        guestFeatures |= (1ULL << VIRTIO_SCSI_F_HOTPLUG);
326
    }
327
    if (!NT_SUCCESS(virtio_set_features(&adaptExt->vdev, guestFeatures))) {
328
        RhelDbgPrint(TRACE_LEVEL_FATAL, " virtio_set_features failed\n");
329
    }
330

331
EXIT_FN();
332
}
333

334

335
BOOLEAN
336
InitVirtIODevice(
337
    IN PVOID DeviceExtension
338
    )
339
{
340
    PADAPTER_EXTENSION adaptExt = (PADAPTER_EXTENSION)DeviceExtension;
341
    NTSTATUS status;
342

343
    status = virtio_device_initialize(
344
        &adaptExt->vdev,
345
        &VioScsiSystemOps,
346
        adaptExt,
347
        adaptExt->msix_enabled);
348
    if (!NT_SUCCESS(status)) {
349
        LogError(adaptExt,
350
                SP_INTERNAL_ADAPTER_ERROR,
351
                __LINE__);
352
        RhelDbgPrint(TRACE_LEVEL_FATAL, " Failed to initialize virtio device, error %x\n", status);
353
        return FALSE;
354
    }
355
    return TRUE;
356
}
357

358
BOOLEAN
359
InitHW(
360
    IN PVOID DeviceExtension,
361
    IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
362
    )
363
{
364
    PACCESS_RANGE      accessRange;
365
    PADAPTER_EXTENSION adaptExt;
366
    ULONG pci_cfg_len, i;
367

368
ENTER_FN();
369
    adaptExt = (PADAPTER_EXTENSION)DeviceExtension;
370
    adaptExt->system_io_bus_number = ConfigInfo->SystemIoBusNumber;
371
    adaptExt->slot_number = ConfigInfo->SlotNumber;
372

373
    /* read PCI config space */
374
    pci_cfg_len = StorPortGetBusData(
375
        DeviceExtension,
376
        PCIConfiguration,
377
        ConfigInfo->SystemIoBusNumber,
378
        (ULONG)ConfigInfo->SlotNumber,
379
        (PVOID)&adaptExt->pci_config_buf,
380
        sizeof(adaptExt->pci_config_buf));
381

382
    if (pci_cfg_len != sizeof(adaptExt->pci_config_buf)) {
383
        LogError(DeviceExtension,
384
                SP_INTERNAL_ADAPTER_ERROR,
385
                __LINE__);
386
        RhelDbgPrint(TRACE_LEVEL_FATAL, " CANNOT READ PCI CONFIGURATION SPACE %d\n", pci_cfg_len);
387
        return FALSE;
388
    }
389

390
    {
391
        UCHAR CapOffset;
392
        PPCI_MSIX_CAPABILITY pMsixCapOffset;
393
        PPCI_COMMON_HEADER   pPciComHeader;
394
        pPciComHeader = &adaptExt->pci_config;
395
        if ((pPciComHeader->Status & PCI_STATUS_CAPABILITIES_LIST) == 0)
396
        {
397
            RhelDbgPrint(TRACE_LEVEL_INFORMATION, " NO CAPABILITIES_LIST\n");
398
        }
399
        else
400
        {
401
            if ((pPciComHeader->HeaderType & (~PCI_MULTIFUNCTION)) == PCI_DEVICE_TYPE)
402
            {
403
                CapOffset = pPciComHeader->u.type0.CapabilitiesPtr;
404
                while (CapOffset != 0)
405
                {
406
                    pMsixCapOffset = (PPCI_MSIX_CAPABILITY)&adaptExt->pci_config_buf[CapOffset];
407
                    if (pMsixCapOffset->Header.CapabilityID == PCI_CAPABILITY_ID_MSIX)
408
                    {
409
                        RhelDbgPrint(TRACE_LEVEL_INFORMATION, "MessageControl.TableSize = %d\n", pMsixCapOffset->MessageControl.TableSize);
410
                        RhelDbgPrint(TRACE_LEVEL_INFORMATION, "MessageControl.FunctionMask = %d\n", pMsixCapOffset->MessageControl.FunctionMask);
411
                        RhelDbgPrint(TRACE_LEVEL_INFORMATION, "MessageControl.MSIXEnable = %d\n", pMsixCapOffset->MessageControl.MSIXEnable);
412

413
                        RhelDbgPrint(TRACE_LEVEL_INFORMATION, " MessageTable = %lu\n", pMsixCapOffset->MessageTable.TableOffset);
414
                        RhelDbgPrint(TRACE_LEVEL_INFORMATION, " PBATable = %lu\n", pMsixCapOffset->PBATable.TableOffset);
415
                        adaptExt->msix_enabled = (pMsixCapOffset->MessageControl.MSIXEnable == 1);
416
                    } else
417
                    {
418
                        RhelDbgPrint(TRACE_LEVEL_INFORMATION, " CapabilityID = %x, Next CapOffset = %x\n", pMsixCapOffset->Header.CapabilityID, CapOffset);
419
                    }
420
                    CapOffset = pMsixCapOffset->Header.Next;
421
                }
422
                RhelDbgPrint(TRACE_LEVEL_INFORMATION, " msix_enabled = %d\n", adaptExt->msix_enabled);
423
            } else
424
            {
425
                RhelDbgPrint(TRACE_LEVEL_FATAL, " NOT A PCI_DEVICE_TYPE\n");
426
            }
427
        }
428
    }
429

430
    /* initialize the pci_bars array */
431
    for (i = 0; i < ConfigInfo->NumberOfAccessRanges; i++) {
432
        accessRange = *ConfigInfo->AccessRanges + i;
433
        if (accessRange->RangeLength != 0) {
434
            int iBar = virtio_get_bar_index(&adaptExt->pci_config, accessRange->RangeStart);
435
            if (iBar == -1) {
436
                RhelDbgPrint(TRACE_LEVEL_FATAL,
437
                             " Cannot get index for BAR %I64d\n", accessRange->RangeStart.QuadPart);
438
                return FALSE;
439
            }
440
            adaptExt->pci_bars[iBar].BasePA = accessRange->RangeStart;
441
            adaptExt->pci_bars[iBar].uLength = accessRange->RangeLength;
442
            adaptExt->pci_bars[iBar].bPortSpace = !accessRange->RangeInMemory;
443
        }
444
    }
445

446
    /* initialize the virtual device */
447
    if (!InitVirtIODevice(DeviceExtension)) {
448
        return FALSE;
449
    }
450

451
EXIT_FN();
452
    return TRUE;
453
}
454

455
BOOLEAN
456
SynchronizedKickEventRoutine(
457
    IN PVOID DeviceExtension,
458
    IN PVOID Context
459
    )
460
{
461
    PADAPTER_EXTENSION  adaptExt = (PADAPTER_EXTENSION)DeviceExtension;
462
    PVirtIOSCSIEventNode eventNode   = (PVirtIOSCSIEventNode) Context;
463
    PVOID               va = NULL;
464
    ULONGLONG           pa = 0;
465

466
ENTER_FN();
467
    if (virtqueue_add_buf(adaptExt->vq[VIRTIO_SCSI_EVENTS_QUEUE],
468
                     &eventNode->sg,
469
                     0, 1,
470
                     eventNode, va, pa) >= 0){
471
        virtqueue_kick(adaptExt->vq[VIRTIO_SCSI_EVENTS_QUEUE]);
472
EXIT_FN();
473
        return TRUE;
474
    }
475
EXIT_ERR();
476
    return FALSE;
477
}
478

479

480
BOOLEAN
481
KickEvent(
482
    IN PVOID DeviceExtension,
483
    IN PVirtIOSCSIEventNode EventNode
484
    )
485
{
486
    PADAPTER_EXTENSION adaptExt;
487
    ULONG              fragLen;
488

489
ENTER_FN();
490
    adaptExt = (PADAPTER_EXTENSION)DeviceExtension;
491
    RtlZeroMemory((PVOID)EventNode, sizeof(VirtIOSCSIEventNode));
492
    EventNode->sg.physAddr = StorPortGetPhysicalAddress(DeviceExtension, NULL, &EventNode->event, &fragLen);
493
    EventNode->sg.length   = sizeof(VirtIOSCSIEvent);
494
    return SynchronizedKickEventRoutine(DeviceExtension, (PVOID)EventNode);
495
EXIT_FN();
496
}
497

498
VOID
499
//FORCEINLINE
500
VioScsiVQLock(
501
    IN PVOID DeviceExtension,
502
    IN ULONG MessageID,
503
    IN OUT PSTOR_LOCK_HANDLE LockHandle,
504
    IN BOOLEAN isr
505
    )
506
{
507
    PADAPTER_EXTENSION  adaptExt = (PADAPTER_EXTENSION)DeviceExtension;
508
    ULONG               QueueNumber = MESSAGE_TO_QUEUE(MessageID);
509
    ENTER_FN();
510

511
    if (!isr) {
512
        if (adaptExt->msix_enabled) {
513
            // Queue numbers start at 0, message ids at 1.
514
            NT_ASSERT(MessageID > VIRTIO_SCSI_REQUEST_QUEUE_0);
515
            if (QueueNumber >= (adaptExt->num_queues + VIRTIO_SCSI_REQUEST_QUEUE_0)) {
516
                QueueNumber %= adaptExt->num_queues;
517
            }
518
            StorPortAcquireSpinLock(DeviceExtension, DpcLock, &adaptExt->dpc[QueueNumber - VIRTIO_SCSI_REQUEST_QUEUE_0], LockHandle);
519
        }
520
        else {
521
            StorPortAcquireSpinLock(DeviceExtension, InterruptLock, NULL, LockHandle);
522
        }
523
    }
524
EXIT_FN();
525
}
526

527
VOID
528
//FORCEINLINE
529
VioScsiVQUnlock(
530
    IN PVOID DeviceExtension,
531
    IN ULONG MessageID,
532
    IN PSTOR_LOCK_HANDLE LockHandle,
533
    IN BOOLEAN isr
534
    )
535
{
536
ENTER_FN();
537
    if (!isr) {
538
        StorPortReleaseSpinLock(DeviceExtension, LockHandle);
539
    }
540
EXIT_FN();
541
}
542

543
VOID FirmwareRequest(
544
    IN PVOID DeviceExtension,
545
    IN PSRB_TYPE Srb
546
    )
547
{
548
    PADAPTER_EXTENSION  adaptExt;
549
    PSRB_EXTENSION      srbExt   = NULL;
550
    ULONG                   dataLen = 0;
551
    PSRB_IO_CONTROL         srbControl = NULL;
552
    PFIRMWARE_REQUEST_BLOCK firmwareRequest = NULL;
553
ENTER_FN();
554
    adaptExt = (PADAPTER_EXTENSION)DeviceExtension;
555
    srbExt = SRB_EXTENSION(Srb);
556
    srbControl = (PSRB_IO_CONTROL)SRB_DATA_BUFFER(Srb);
557
    dataLen = SRB_DATA_TRANSFER_LENGTH(Srb);
558
    if (dataLen < (sizeof(SRB_IO_CONTROL) + sizeof(FIRMWARE_REQUEST_BLOCK))) {
559
        srbControl->ReturnCode = FIRMWARE_STATUS_INVALID_PARAMETER;
560
        SRB_SET_SRB_STATUS(Srb, SRB_STATUS_BAD_SRB_BLOCK_LENGTH);
561
        RhelDbgPrint(TRACE_LEVEL_ERROR,
562
                         " FirmwareRequest Bad Block Length  %ul\n", dataLen);
563
        return;
564
    }
565

566
    firmwareRequest = (PFIRMWARE_REQUEST_BLOCK)(srbControl + 1);
567
    switch (firmwareRequest->Function) {
568

569
    case FIRMWARE_FUNCTION_GET_INFO: {
570
        PSTORAGE_FIRMWARE_INFO_V2   firmwareInfo;
571
        firmwareInfo = (PSTORAGE_FIRMWARE_INFO_V2)((PUCHAR)srbControl + firmwareRequest->DataBufferOffset);
572
        RhelDbgPrint(TRACE_LEVEL_INFORMATION,
573
                         " FIRMWARE_FUNCTION_GET_INFO \n");
574
        if ((firmwareInfo->Version >= STORAGE_FIRMWARE_INFO_STRUCTURE_VERSION_V2) ||
575
            (firmwareInfo->Size >= sizeof(STORAGE_FIRMWARE_INFO_V2))) {
576
            firmwareInfo->Version = STORAGE_FIRMWARE_INFO_STRUCTURE_VERSION_V2;
577
            firmwareInfo->Size = sizeof(STORAGE_FIRMWARE_INFO_V2);
578

579
            firmwareInfo->UpgradeSupport = TRUE;
580

581
            firmwareInfo->SlotCount = 1;
582
            firmwareInfo->ActiveSlot = 0;
583
            firmwareInfo->PendingActivateSlot = STORAGE_FIRMWARE_INFO_INVALID_SLOT;
584
            firmwareInfo->FirmwareShared = FALSE;
585
            firmwareInfo->ImagePayloadAlignment = PAGE_SIZE;
586
            firmwareInfo->ImagePayloadMaxSize = PAGE_SIZE;
587

588
            if (firmwareRequest->DataBufferLength >= (sizeof(STORAGE_FIRMWARE_INFO_V2) + sizeof(STORAGE_FIRMWARE_SLOT_INFO_V2))) {
589
                firmwareInfo->Slot[0].SlotNumber = 0;
590
                firmwareInfo->Slot[0].ReadOnly = FALSE;
591
                StorPortCopyMemory(&firmwareInfo->Slot[0].Revision, &adaptExt->fw_ver, sizeof (adaptExt->fw_ver));
592
                srbControl->ReturnCode = FIRMWARE_STATUS_SUCCESS;
593
            } else {
594
                firmwareRequest->DataBufferLength = sizeof(STORAGE_FIRMWARE_INFO_V2) + sizeof(STORAGE_FIRMWARE_SLOT_INFO_V2);
595
                srbControl->ReturnCode = FIRMWARE_STATUS_OUTPUT_BUFFER_TOO_SMALL;
596
            }
597
            SRB_SET_SRB_STATUS(Srb, SRB_STATUS_SUCCESS);
598
        }
599
        else {
600
            RhelDbgPrint(TRACE_LEVEL_ERROR,
601
                         " Wrong Version %ul or Size %ul\n", firmwareInfo->Version, firmwareInfo->Size);
602
            srbControl->ReturnCode = FIRMWARE_STATUS_INVALID_PARAMETER;
603
            SRB_SET_SRB_STATUS(Srb, SRB_STATUS_BAD_SRB_BLOCK_LENGTH);
604
        }
605
    }
606
    break;
607
    case FIRMWARE_FUNCTION_DOWNLOAD: {
608
        PSTORAGE_FIRMWARE_DOWNLOAD_V2   firmwareDwnld;
609
        firmwareDwnld = (PSTORAGE_FIRMWARE_DOWNLOAD_V2)((PUCHAR)srbControl + firmwareRequest->DataBufferOffset);
610
        RhelDbgPrint(TRACE_LEVEL_INFORMATION,
611
            " FIRMWARE_FUNCTION_DOWNLOAD \n");
612
        if ((firmwareDwnld->Version >= STORAGE_FIRMWARE_DOWNLOAD_STRUCTURE_VERSION_V2) ||
613
            (firmwareDwnld->Size >= sizeof(STORAGE_FIRMWARE_DOWNLOAD_V2))) {
614
            firmwareDwnld->Version = STORAGE_FIRMWARE_DOWNLOAD_STRUCTURE_VERSION_V2;
615
            firmwareDwnld->Size = sizeof(STORAGE_FIRMWARE_DOWNLOAD_V2);
616
            adaptExt->fw_ver++;
617
            srbControl->ReturnCode = FIRMWARE_STATUS_SUCCESS;
618
            SRB_SET_SRB_STATUS(Srb, SRB_STATUS_SUCCESS);
619
        }
620
        else {
621
            RhelDbgPrint(TRACE_LEVEL_ERROR,
622
                " Wrong Version %ul or Size %ul\n", firmwareDwnld->Version, firmwareDwnld->Size);
623
            srbControl->ReturnCode = FIRMWARE_STATUS_INVALID_PARAMETER;
624
            SRB_SET_SRB_STATUS(Srb, SRB_STATUS_BAD_SRB_BLOCK_LENGTH);
625
        }
626
    }
627
    break;
628
    case FIRMWARE_FUNCTION_ACTIVATE: {
629
        PSTORAGE_FIRMWARE_ACTIVATE firmwareActivate;
630
        firmwareActivate = (PSTORAGE_FIRMWARE_ACTIVATE)((PUCHAR)srbControl + firmwareRequest->DataBufferOffset);
631
        if ((firmwareActivate->Version == STORAGE_FIRMWARE_ACTIVATE_STRUCTURE_VERSION) ||
632
            (firmwareActivate->Size >= sizeof(STORAGE_FIRMWARE_ACTIVATE))) {
633
            firmwareActivate->Version = STORAGE_FIRMWARE_ACTIVATE_STRUCTURE_VERSION;
634
            firmwareActivate->Size = sizeof(STORAGE_FIRMWARE_ACTIVATE);
635
            srbControl->ReturnCode = FIRMWARE_STATUS_SUCCESS;
636
            SRB_SET_SRB_STATUS(Srb, SRB_STATUS_SUCCESS);
637
        }
638
        else {
639
            RhelDbgPrint(TRACE_LEVEL_ERROR,
640
                " Wrong Version %ul or Size %ul\n", firmwareActivate->Version, firmwareActivate->Size);
641
            srbControl->ReturnCode = FIRMWARE_STATUS_INVALID_PARAMETER;
642
            SRB_SET_SRB_STATUS(Srb, SRB_STATUS_BAD_SRB_BLOCK_LENGTH);
643
        }
644
        RhelDbgPrint(TRACE_LEVEL_VERBOSE,
645
            " FIRMWARE_FUNCTION_ACTIVATE \n");
646
    }
647
    break;
648
    default:
649
        RhelDbgPrint(TRACE_LEVEL_INFORMATION,
650
                     " Unsupported Function %ul\n", firmwareRequest->Function);
651
        SRB_SET_SRB_STATUS(Srb, SRB_STATUS_INVALID_REQUEST);
652
        break;
653
    }
654
EXIT_FN();
655
}
656

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.