VirtualBox

source: vbox/trunk/src/VBox/Devices/Storage/VSCSI/VSCSIDevice.cpp@ 104932

Last change on this file since 104932 was 104580, checked in by vboxsync, 7 months ago

Devies/Storage/VSCSI: Call scsiBE2H_U16() jsut once outside of RT_MIN() to avoid calling it twice (harmless, scsiBE2H_U16() has no side effects but a compiler might generate non-optimal code), missing call to vscsiDeviceReqComplete(), bugref:3409

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.6 KB
Line 
1/* $Id: VSCSIDevice.cpp 104580 2024-05-13 08:48:29Z vboxsync $ */
2/** @file
3 * Virtual SCSI driver: Device handling
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_VSCSI
33#include <VBox/log.h>
34#include <VBox/err.h>
35#include <VBox/types.h>
36#include <VBox/vscsi.h>
37#include <iprt/assert.h>
38#include <iprt/mem.h>
39#include <iprt/string.h>
40
41#include "VSCSIInternal.h"
42
43/**
44 * Checks if a specific LUN exists fir the SCSI device
45 *
46 * @returns true if the LUN is present
47 * false otherwise
48 * @param pVScsiDevice The SCSI device instance.
49 * @param iLun The LUN to check for.
50 */
51DECLINLINE(bool) vscsiDeviceLunIsPresent(PVSCSIDEVICEINT pVScsiDevice, uint32_t iLun)
52{
53 return ( iLun < pVScsiDevice->cLunsMax
54 && pVScsiDevice->papVScsiLun[iLun] != NULL);
55}
56
57/**
58 * Process a request common for all device types.
59 *
60 * @returns Flag whether we could handle the request.
61 * @param pVScsiDevice The virtual SCSI device instance.
62 * @param pVScsiReq The SCSI request.
63 * @param prcReq The final return value if the request was handled.
64 */
65static bool vscsiDeviceReqProcess(PVSCSIDEVICEINT pVScsiDevice, PVSCSIREQINT pVScsiReq,
66 int *prcReq)
67{
68 bool fProcessed = true;
69
70 LogFlowFunc(("CDB: %.*Rhxs Cmd: %s\n", pVScsiReq->cbCDB, pVScsiReq->pbCDB, SCSICmdText(pVScsiReq->pbCDB[0])));
71
72 if (!pVScsiReq->cbCDB)
73 {
74 *prcReq = vscsiReqSenseErrorSet(&pVScsiDevice->VScsiSense, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST,
75 SCSI_ASC_ILLEGAL_OPCODE, 0x00);
76 return true;
77 }
78
79 switch (pVScsiReq->pbCDB[0])
80 {
81 case SCSI_INQUIRY:
82 {
83 if (!vscsiDeviceLunIsPresent(pVScsiDevice, pVScsiReq->iLun))
84 {
85 SCSIINQUIRYDATA ScsiInquiryReply;
86
87 uint16_t cbDataReq = scsiBE2H_U16(&pVScsiReq->pbCDB[3]);
88 vscsiReqSetXferDir(pVScsiReq, VSCSIXFERDIR_T2I);
89 vscsiReqSetXferSize(pVScsiReq, RT_MIN(sizeof(SCSIINQUIRYDATA), cbDataReq));
90 memset(&ScsiInquiryReply, 0, sizeof(ScsiInquiryReply));
91 ScsiInquiryReply.cbAdditional = 31;
92 ScsiInquiryReply.u5PeripheralDeviceType = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_UNKNOWN;
93 ScsiInquiryReply.u3PeripheralQualifier = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_NOT_CONNECTED_NOT_SUPPORTED;
94 RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, (uint8_t *)&ScsiInquiryReply, sizeof(SCSIINQUIRYDATA));
95 *prcReq = vscsiReqSenseOkSet(&pVScsiDevice->VScsiSense, pVScsiReq);
96 }
97 else
98 fProcessed = false; /* Let the LUN process the request because it will provide LUN specific data */
99
100 break;
101 }
102 case SCSI_REPORT_LUNS:
103 {
104 if (pVScsiReq->cbCDB < 10)
105 {
106 *prcReq = vscsiReqSenseErrorSet(&pVScsiDevice->VScsiSense, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST,
107 SCSI_ASC_ILLEGAL_OPCODE, 0x00);
108 break;
109 }
110
111 /*
112 * If allocation length is less than 16 bytes SPC compliant devices have
113 * to return an error.
114 */
115 vscsiReqSetXferDir(pVScsiReq, VSCSIXFERDIR_T2I);
116 vscsiReqSetXferSize(pVScsiReq, scsiBE2H_U32(&pVScsiReq->pbCDB[6]));
117 if (pVScsiReq->cbXfer < 16)
118 *prcReq = vscsiReqSenseErrorSet(&pVScsiDevice->VScsiSense, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
119 else
120 {
121 size_t cbData;
122 uint8_t aReply[16]; /* We report only one LUN. */
123
124 memset(aReply, 0, sizeof(aReply));
125 scsiH2BE_U32(&aReply[0], 8); /* List length starts at position 0. */
126 cbData = RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, sizeof(aReply));
127 if (cbData < 16)
128 *prcReq = vscsiReqSenseErrorSet(&pVScsiDevice->VScsiSense, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
129 else
130 *prcReq = vscsiReqSenseOkSet(&pVScsiDevice->VScsiSense, pVScsiReq);
131 }
132 break;
133 }
134 case SCSI_TEST_UNIT_READY:
135 {
136 vscsiReqSetXferDir(pVScsiReq, VSCSIXFERDIR_NONE);
137 if ( vscsiDeviceLunIsPresent(pVScsiDevice, pVScsiReq->iLun)
138 && pVScsiDevice->papVScsiLun[pVScsiReq->iLun]->fReady)
139 *prcReq = vscsiReqSenseOkSet(&pVScsiDevice->VScsiSense, pVScsiReq);
140 else
141 fProcessed = false; /* The LUN (if present) will provide details. */
142 break;
143 }
144 case SCSI_REQUEST_SENSE:
145 {
146 if (pVScsiReq->cbCDB < 5)
147 {
148 *prcReq = vscsiReqSenseErrorSet(&pVScsiDevice->VScsiSense, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST,
149 SCSI_ASC_ILLEGAL_OPCODE, 0x00);
150 break;
151 }
152
153 vscsiReqSetXferDir(pVScsiReq, VSCSIXFERDIR_T2I);
154 vscsiReqSetXferSize(pVScsiReq, pVScsiReq->pbCDB[4]);
155
156 /* Descriptor format sense data is not supported and results in an error. */
157 if ((pVScsiReq->pbCDB[1] & 0x1) != 0)
158 *prcReq = vscsiReqSenseErrorSet(&pVScsiDevice->VScsiSense, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
159 else
160 *prcReq = vscsiReqSenseCmd(&pVScsiDevice->VScsiSense, pVScsiReq);
161 break;
162 }
163#if 0
164 case SCSI_MAINTENANCE_IN:
165 {
166 if (pVScsiReq->cbCDB < 8)
167 {
168 *prcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST,
169 SCSI_ASC_ILLEGAL_OPCODE, 0x00);
170 break;
171 }
172
173 if (pVScsiReq->pbCDB[1] == SCSI_MAINTENANCE_IN_REPORT_SUPP_OPC)
174 {
175 /*
176 * If the LUN is present and has the CDB info set we will execute the command, otherwise
177 * just fail with an illegal request error.
178 */
179 if (vscsiDeviceLunIsPresent(pVScsiDevice, pVScsiReq->iLun))
180 {
181 PVSCSILUNINT pVScsiLun = pVScsiDevice->papVScsiLun[pVScsiReq->iLun];
182 if (pVScsiLun->pVScsiLunDesc->paSupOpcInfo)
183 {
184 bool fTimeoutDesc = RT_BOOL(pVScsiReq->pbCDB[2] & 0x80);
185 uint8_t u8ReportMode = pVScsiReq->pbCDB[2] & 0x7;
186 uint8_t u8Opc = pVScsiReq->pbCDB[3];
187 uint16_t u16SvcAction = scsiBE2H_U16(&pVScsiReq->pbCDB[4]);
188 uint16_t cbData = scsiBE2H_U16(&pVScsiReq->pbCDB[6]);
189
190 switch (u8ReportMode)
191 {
192 case 0:
193 *prcReq = vscsiDeviceReportAllSupportedOpc(pVScsiLun, pVScsiReq, fTimeoutDesc, cbData);
194 break;
195 case 1:
196 *prcReq = vscsiDeviceReportOpc(pVScsiLun, pVScsiReq, u8Opc, fTimeoutDesc, cbData);
197 break;
198 case 2:
199 *prcReq = vscsiDeviceReportOpc(pVScsiLun, pVScsiReq, u8Opc, fTimeoutDesc, cbData);
200 break;
201 default:
202 *prcReq = vscsiReqSenseErrorSet(&pVScsiDevice->VScsiSense, pVScsiReq,
203 SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
204 }
205 }
206 else
207 *prcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE, 0x00);
208 }
209 else
210 *prcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE, 0x00);
211 }
212 else
213 fProcessed = false; /* Might also be the SEND KEY MMC command. */
214 }
215#endif
216 default:
217 fProcessed = false;
218 }
219
220 return fProcessed;
221}
222
223
224void vscsiDeviceReqComplete(PVSCSIDEVICEINT pVScsiDevice, PVSCSIREQINT pVScsiReq,
225 int rcScsiCode, bool fRedoPossible, int rcReq)
226{
227 pVScsiDevice->pfnVScsiReqCompleted(pVScsiDevice, pVScsiDevice->pvVScsiDeviceUser,
228 pVScsiReq->pvVScsiReqUser, rcScsiCode, fRedoPossible,
229 rcReq, pVScsiReq->cbXfer, pVScsiReq->enmXferDir, pVScsiReq->cbSenseWritten);
230
231 if (pVScsiReq->pvLun)
232 {
233 if (vscsiDeviceLunIsPresent(pVScsiDevice, pVScsiReq->iLun))
234 {
235 PVSCSILUNINT pVScsiLun = pVScsiDevice->papVScsiLun[pVScsiReq->iLun];
236 pVScsiLun->pVScsiLunDesc->pfnVScsiLunReqFree(pVScsiLun, pVScsiReq, pVScsiReq->pvLun);
237 }
238 else
239 AssertLogRelMsgFailed(("vscsiDeviceReqComplete: LUN %u for VSCSI request %#p is not present but there is LUN specific data allocated\n",
240 pVScsiReq->iLun, pVScsiReq));
241
242 pVScsiReq->pvLun = NULL;
243 }
244
245 RTMemCacheFree(pVScsiDevice->hCacheReq, pVScsiReq);
246}
247
248
249VBOXDDU_DECL(int) VSCSIDeviceCreate(PVSCSIDEVICE phVScsiDevice,
250 PFNVSCSIREQCOMPLETED pfnVScsiReqCompleted,
251 void *pvVScsiDeviceUser)
252{
253 int rc = VINF_SUCCESS;
254 PVSCSIDEVICEINT pVScsiDevice = NULL;
255
256 AssertPtrReturn(phVScsiDevice, VERR_INVALID_POINTER);
257 AssertPtrReturn(pfnVScsiReqCompleted, VERR_INVALID_POINTER);
258
259 pVScsiDevice = (PVSCSIDEVICEINT)RTMemAllocZ(sizeof(VSCSIDEVICEINT));
260 if (!pVScsiDevice)
261 return VERR_NO_MEMORY;
262
263 pVScsiDevice->pfnVScsiReqCompleted = pfnVScsiReqCompleted;
264 pVScsiDevice->pvVScsiDeviceUser = pvVScsiDeviceUser;
265 pVScsiDevice->cLunsAttached = 0;
266 pVScsiDevice->cLunsMax = 0;
267 pVScsiDevice->papVScsiLun = NULL;
268 vscsiSenseInit(&pVScsiDevice->VScsiSense);
269
270 rc = RTMemCacheCreate(&pVScsiDevice->hCacheReq, sizeof(VSCSIREQINT), 0, UINT32_MAX,
271 NULL, NULL, NULL, 0);
272 if (RT_SUCCESS(rc))
273 {
274 *phVScsiDevice = pVScsiDevice;
275 LogFlow(("%s: hVScsiDevice=%#p -> VINF_SUCCESS\n", __FUNCTION__, pVScsiDevice));
276 return VINF_SUCCESS;
277 }
278
279 RTMemFree(pVScsiDevice);
280
281 return rc;
282}
283
284
285VBOXDDU_DECL(int) VSCSIDeviceDestroy(VSCSIDEVICE hVScsiDevice)
286{
287 AssertPtrReturn(hVScsiDevice, VERR_INVALID_HANDLE);
288
289 PVSCSIDEVICEINT pVScsiDevice = (PVSCSIDEVICEINT)hVScsiDevice;
290
291 if (pVScsiDevice->cLunsAttached > 0)
292 return VERR_VSCSI_LUN_ATTACHED_TO_DEVICE;
293
294 if (pVScsiDevice->papVScsiLun)
295 RTMemFree(pVScsiDevice->papVScsiLun);
296
297 RTMemCacheDestroy(pVScsiDevice->hCacheReq);
298 RTMemFree(pVScsiDevice);
299
300 return VINF_SUCCESS;;
301}
302
303
304VBOXDDU_DECL(int) VSCSIDeviceLunAttach(VSCSIDEVICE hVScsiDevice, VSCSILUN hVScsiLun, uint32_t iLun)
305{
306 PVSCSIDEVICEINT pVScsiDevice = (PVSCSIDEVICEINT)hVScsiDevice;
307 PVSCSILUNINT pVScsiLun = (PVSCSILUNINT)hVScsiLun;
308 int rc = VINF_SUCCESS;
309
310 /* Parameter checks */
311 AssertPtrReturn(pVScsiDevice, VERR_INVALID_HANDLE);
312 AssertPtrReturn(pVScsiLun, VERR_INVALID_HANDLE);
313 AssertReturn(iLun < VSCSI_DEVICE_LUN_MAX, VERR_VSCSI_LUN_INVALID);
314 AssertReturn(!pVScsiLun->pVScsiDevice, VERR_VSCSI_LUN_ATTACHED_TO_DEVICE);
315
316 if (iLun >= pVScsiDevice->cLunsMax)
317 {
318 PPVSCSILUNINT papLunOld = pVScsiDevice->papVScsiLun;
319
320 pVScsiDevice->papVScsiLun = (PPVSCSILUNINT)RTMemAllocZ((iLun + 1) * sizeof(PVSCSILUNINT));
321 if (pVScsiDevice->papVScsiLun)
322 {
323 for (uint32_t i = 0; i < pVScsiDevice->cLunsMax; i++)
324 pVScsiDevice->papVScsiLun[i] = papLunOld[i];
325
326 if (papLunOld)
327 RTMemFree(papLunOld);
328
329 pVScsiDevice->cLunsMax = iLun + 1;
330 }
331 else
332 rc = VERR_NO_MEMORY;
333 }
334
335 if (RT_SUCCESS(rc))
336 {
337 pVScsiLun->pVScsiDevice = pVScsiDevice;
338 pVScsiDevice->papVScsiLun[iLun] = pVScsiLun;
339 pVScsiDevice->cLunsAttached++;
340 }
341
342 return rc;
343}
344
345
346VBOXDDU_DECL(int) VSCSIDeviceLunDetach(VSCSIDEVICE hVScsiDevice, uint32_t iLun,
347 PVSCSILUN phVScsiLun)
348{
349 PVSCSIDEVICEINT pVScsiDevice = (PVSCSIDEVICEINT)hVScsiDevice;
350
351 /* Parameter checks */
352 AssertPtrReturn(pVScsiDevice, VERR_INVALID_HANDLE);
353 AssertPtrReturn(phVScsiLun, VERR_INVALID_POINTER);
354 AssertReturn(iLun < VSCSI_DEVICE_LUN_MAX, VERR_VSCSI_LUN_INVALID);
355 AssertReturn(iLun < pVScsiDevice->cLunsMax, VERR_VSCSI_LUN_NOT_ATTACHED);
356 AssertPtrReturn(pVScsiDevice->papVScsiLun[iLun], VERR_VSCSI_LUN_NOT_ATTACHED);
357
358 PVSCSILUNINT pVScsiLun = pVScsiDevice->papVScsiLun[iLun];
359
360 pVScsiLun->pVScsiDevice = NULL;
361 *phVScsiLun = pVScsiLun;
362 pVScsiDevice->papVScsiLun[iLun] = NULL;
363 pVScsiDevice->cLunsAttached--;
364
365 return VINF_SUCCESS;
366}
367
368
369VBOXDDU_DECL(int) VSCSIDeviceLunQueryType(VSCSIDEVICE hVScsiDevice, uint32_t iLun,
370 PVSCSILUNTYPE pEnmLunType)
371{
372 PVSCSIDEVICEINT pVScsiDevice = (PVSCSIDEVICEINT)hVScsiDevice;
373
374 /* Parameter checks */
375 AssertPtrReturn(pVScsiDevice, VERR_INVALID_HANDLE);
376 AssertPtrReturn(pEnmLunType, VERR_INVALID_POINTER);
377 AssertReturn(iLun < VSCSI_DEVICE_LUN_MAX, VERR_VSCSI_LUN_INVALID);
378 AssertReturn(iLun < pVScsiDevice->cLunsMax, VERR_VSCSI_LUN_NOT_ATTACHED);
379 AssertPtrReturn(pVScsiDevice->papVScsiLun[iLun], VERR_VSCSI_LUN_NOT_ATTACHED);
380
381 PVSCSILUNINT hVScsiLun = pVScsiDevice->papVScsiLun[iLun];
382 *pEnmLunType = hVScsiLun->pVScsiLunDesc->enmLunType;
383
384 return VINF_SUCCESS;
385}
386
387
388VBOXDDU_DECL(int) VSCSIDeviceReqEnqueue(VSCSIDEVICE hVScsiDevice, VSCSIREQ hVScsiReq)
389{
390 PVSCSIDEVICEINT pVScsiDevice = (PVSCSIDEVICEINT)hVScsiDevice;
391 PVSCSIREQINT pVScsiReq = (PVSCSIREQINT)hVScsiReq;
392 int rc = VINF_SUCCESS;
393
394 /* Parameter checks */
395 AssertPtrReturn(pVScsiDevice, VERR_INVALID_HANDLE);
396 AssertPtrReturn(pVScsiReq, VERR_INVALID_HANDLE);
397
398 /* Check if this request can be handled by us */
399 int rcReq;
400 bool fProcessed = vscsiDeviceReqProcess(pVScsiDevice, pVScsiReq, &rcReq);
401 if (!fProcessed)
402 {
403 /* Pass to the LUN driver */
404 if (vscsiDeviceLunIsPresent(pVScsiDevice, pVScsiReq->iLun))
405 {
406 PVSCSILUNINT pVScsiLun = pVScsiDevice->papVScsiLun[pVScsiReq->iLun];
407 PVSCSILUNDESC pVScsiLunDesc = pVScsiLun->pVScsiLunDesc;
408 uint8_t const bOpc = pVScsiReq->pbCDB[0];
409 uint8_t const cbCdbMin = pVScsiLunDesc->pacbCdbOpc[bOpc];
410
411 /* Fail if the opcode is not supported or the CDB is too short. */
412 if ( cbCdbMin != VSCSI_LUN_CDB_SZ_INVALID
413 && pVScsiReq->cbCDB >= cbCdbMin)
414 rc = pVScsiLunDesc->pfnVScsiLunReqProcess(pVScsiLun, pVScsiReq);
415 else
416 {
417 /*
418 * CDB length is smaller than what the LUN expects, respond with an
419 * ILLEGAL OPCODE error.
420 */
421 vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST,
422 SCSI_ASC_ILLEGAL_OPCODE, 0x00);
423
424 vscsiDeviceReqComplete(pVScsiDevice, pVScsiReq,
425 SCSI_STATUS_CHECK_CONDITION, false, VINF_SUCCESS);
426 }
427 }
428 else
429 {
430 /* LUN not present, report error. */
431 vscsiReqSenseErrorSet(&pVScsiDevice->VScsiSense, pVScsiReq,
432 SCSI_SENSE_ILLEGAL_REQUEST,
433 SCSI_ASC_LOGICAL_UNIT_DOES_NOT_RESPOND_TO_SELECTION,
434 0x00);
435
436 vscsiDeviceReqComplete(pVScsiDevice, pVScsiReq,
437 SCSI_STATUS_CHECK_CONDITION, false, VINF_SUCCESS);
438 }
439 }
440 else
441 vscsiDeviceReqComplete(pVScsiDevice, pVScsiReq,
442 rcReq, false, VINF_SUCCESS);
443
444 return rc;
445}
446
447
448VBOXDDU_DECL(int) VSCSIDeviceReqCreate(VSCSIDEVICE hVScsiDevice, PVSCSIREQ phVScsiReq,
449 uint32_t iLun, uint8_t *pbCDB, size_t cbCDB,
450 size_t cbSGList, unsigned cSGListEntries,
451 PCRTSGSEG paSGList, uint8_t *pbSense,
452 size_t cbSense, void *pvVScsiReqUser)
453{
454 RT_NOREF1(cbSGList);
455 PVSCSIDEVICEINT pVScsiDevice = (PVSCSIDEVICEINT)hVScsiDevice;
456 PVSCSIREQINT pVScsiReq = NULL;
457
458 /* Parameter checks */
459 AssertPtrReturn(pVScsiDevice, VERR_INVALID_HANDLE);
460 AssertPtrReturn(phVScsiReq, VERR_INVALID_POINTER);
461 AssertPtrReturn(pbCDB, VERR_INVALID_PARAMETER);
462 AssertReturn(cbCDB > 0, VERR_INVALID_PARAMETER);
463
464 pVScsiReq = (PVSCSIREQINT)RTMemCacheAlloc(pVScsiDevice->hCacheReq);
465 if (!pVScsiReq)
466 return VERR_NO_MEMORY;
467
468 pVScsiReq->iLun = iLun;
469 pVScsiReq->pbCDB = pbCDB;
470 pVScsiReq->cbCDB = cbCDB;
471 pVScsiReq->pbSense = pbSense;
472 pVScsiReq->cbSense = cbSense;
473 pVScsiReq->pvVScsiReqUser = pvVScsiReqUser;
474 pVScsiReq->cbXfer = 0;
475 pVScsiReq->pvLun = NULL;
476 pVScsiReq->enmXferDir = VSCSIXFERDIR_UNKNOWN;
477 pVScsiReq->cbSenseWritten = 0;
478 RTSgBufInit(&pVScsiReq->SgBuf, paSGList, cSGListEntries);
479
480 *phVScsiReq = pVScsiReq;
481
482 return VINF_SUCCESS;
483}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette