VirtualBox

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

Last change on this file since 65620 was 65111, checked in by vboxsync, 8 years ago

Storage/Devices/VSCSI: Make use of the new SCSI inline helpers and remove the the local inlines

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