VirtualBox

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

Last change on this file since 38530 was 38530, checked in by vboxsync, 13 years ago

VSCSI: Implement REQUEST SENSE command

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.8 KB
Line 
1/* $Id: VSCSIDevice.cpp 38530 2011-08-25 14:26:49Z vboxsync $ */
2/** @file
3 * Virtual SCSI driver: Device handling
4 */
5
6/*
7 * Copyright (C) 2006-2010 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#define LOG_GROUP LOG_GROUP_VSCSI
18#include <VBox/log.h>
19#include <VBox/err.h>
20#include <VBox/types.h>
21#include <VBox/vscsi.h>
22#include <iprt/assert.h>
23#include <iprt/mem.h>
24#include <iprt/string.h>
25
26#include "VSCSIInternal.h"
27
28/**
29 * Checks if a specific LUN exists fir the SCSI device
30 *
31 * @returns true if the LUN is present
32 * false otherwise
33 * @param pVScsiDevice The SCSI device instance.
34 * @param iLun The LUN to check for.
35 */
36DECLINLINE(bool) vscsiDeviceLunIsPresent(PVSCSIDEVICEINT pVScsiDevice, uint32_t iLun)
37{
38 return ( iLun < pVScsiDevice->cLunsMax
39 && pVScsiDevice->papVScsiLun[iLun] != NULL);
40}
41
42/**
43 * Process a request common for all device types.
44 *
45 * @returns Flag whether we could handle the request.
46 * @param pVScsiDevice The virtual SCSI device instance.
47 * @param pVScsiReq The SCSi request.
48 * @param prcReq The final return value if the request was handled.
49 */
50static bool vscsiDeviceReqProcess(PVSCSIDEVICEINT pVScsiDevice, PVSCSIREQINT pVScsiReq,
51 int *prcReq)
52{
53 bool fProcessed = true;
54
55 switch (pVScsiReq->pbCDB[0])
56 {
57 case SCSI_INQUIRY:
58 {
59 if (!vscsiDeviceLunIsPresent(pVScsiDevice, pVScsiReq->iLun))
60 {
61 size_t cbData;
62 SCSIINQUIRYDATA ScsiInquiryReply;
63
64 memset(&ScsiInquiryReply, 0, sizeof(ScsiInquiryReply));
65 ScsiInquiryReply.cbAdditional = 31;
66 ScsiInquiryReply.u5PeripheralDeviceType = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_UNKNOWN;
67 ScsiInquiryReply.u3PeripheralQualifier = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_NOT_CONNECTED_NOT_SUPPORTED;
68 cbData = vscsiCopyToIoMemCtx(&pVScsiReq->IoMemCtx, (uint8_t *)&ScsiInquiryReply, sizeof(SCSIINQUIRYDATA));
69 *prcReq = vscsiReqSenseOkSet(&pVScsiDevice->VScsiSense, pVScsiReq);
70 }
71 else
72 fProcessed = false; /* Let the LUN process the request because it will provide LUN specific data */
73
74 break;
75 }
76 case SCSI_REPORT_LUNS:
77 {
78 /*
79 * If allocation length is less than 16 bytes SPC compliant devices have
80 * to return an error.
81 */
82 if (vscsiBE2HU32(&pVScsiReq->pbCDB[6]) < 16)
83 *prcReq = vscsiReqSenseErrorSet(&pVScsiDevice->VScsiSense, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
84 else
85 {
86 size_t cbData;
87 uint8_t aReply[16]; /* We report only one LUN. */
88
89 memset(aReply, 0, sizeof(aReply));
90 vscsiH2BEU32(&aReply[0], 8); /* List length starts at position 0. */
91 cbData = vscsiCopyToIoMemCtx(&pVScsiReq->IoMemCtx, aReply, sizeof(aReply));
92 if (cbData < 16)
93 *prcReq = vscsiReqSenseErrorSet(&pVScsiDevice->VScsiSense, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
94 else
95 *prcReq = vscsiReqSenseOkSet(&pVScsiDevice->VScsiSense, pVScsiReq);
96 }
97 break;
98 }
99 case SCSI_TEST_UNIT_READY:
100 {
101 *prcReq = vscsiReqSenseOkSet(&pVScsiDevice->VScsiSense, pVScsiReq);
102 break;
103 }
104 case SCSI_REQUEST_SENSE:
105 {
106 /* Descriptor format sense data is not supported and results in an error. */
107 if ((pVScsiReq->pbCDB[1] & 0x1) != 0)
108 *prcReq = vscsiReqSenseErrorSet(&pVScsiDevice->VScsiSense, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
109 else
110 *prcReq = vscsiReqSenseCmd(&pVScsiDevice->VScsiSense, pVScsiReq);
111 }
112 default:
113 fProcessed = false;
114 }
115
116 return fProcessed;
117}
118
119
120void vscsiDeviceReqComplete(PVSCSIDEVICEINT pVScsiDevice, PVSCSIREQINT pVScsiReq,
121 int rcScsiCode, bool fRedoPossible, int rcReq)
122{
123 pVScsiDevice->pfnVScsiReqCompleted(pVScsiDevice, pVScsiDevice->pvVScsiDeviceUser,
124 pVScsiReq->pvVScsiReqUser, rcScsiCode, fRedoPossible,
125 rcReq);
126
127 RTMemCacheFree(pVScsiDevice->hCacheReq, pVScsiReq);
128}
129
130
131VBOXDDU_DECL(int) VSCSIDeviceCreate(PVSCSIDEVICE phVScsiDevice,
132 PFNVSCSIREQCOMPLETED pfnVScsiReqCompleted,
133 void *pvVScsiDeviceUser)
134{
135 int rc = VINF_SUCCESS;
136 PVSCSIDEVICEINT pVScsiDevice = NULL;
137
138 AssertPtrReturn(phVScsiDevice, VERR_INVALID_POINTER);
139 AssertPtrReturn(pfnVScsiReqCompleted, VERR_INVALID_POINTER);
140
141 pVScsiDevice = (PVSCSIDEVICEINT)RTMemAllocZ(sizeof(VSCSIDEVICEINT));
142 if (!pVScsiDevice)
143 return VERR_NO_MEMORY;
144
145 pVScsiDevice->pfnVScsiReqCompleted = pfnVScsiReqCompleted;
146 pVScsiDevice->pvVScsiDeviceUser = pvVScsiDeviceUser;
147 pVScsiDevice->cLunsAttached = 0;
148 pVScsiDevice->cLunsMax = 0;
149 pVScsiDevice->papVScsiLun = NULL;
150 vscsiSenseInit(&pVScsiDevice->VScsiSense);
151
152 rc = RTMemCacheCreate(&pVScsiDevice->hCacheReq, sizeof(VSCSIREQINT), 0, UINT32_MAX,
153 NULL, NULL, NULL, 0);
154 if (RT_SUCCESS(rc))
155 {
156 *phVScsiDevice = pVScsiDevice;
157 LogFlow(("%s: hVScsiDevice=%#p -> VINF_SUCCESS\n", __FUNCTION__, pVScsiDevice));
158 return VINF_SUCCESS;
159 }
160
161 RTMemFree(pVScsiDevice);
162
163 return rc;
164}
165
166
167VBOXDDU_DECL(int) VSCSIDeviceDestroy(VSCSIDEVICE hVScsiDevice)
168{
169 AssertPtrReturn(hVScsiDevice, VERR_INVALID_HANDLE);
170
171 PVSCSIDEVICEINT pVScsiDevice = (PVSCSIDEVICEINT)hVScsiDevice;
172
173 if (pVScsiDevice->cLunsAttached > 0)
174 return VERR_VSCSI_LUN_ATTACHED_TO_DEVICE;
175
176 if (pVScsiDevice->papVScsiLun)
177 RTMemFree(pVScsiDevice->papVScsiLun);
178
179 RTMemCacheDestroy(pVScsiDevice->hCacheReq);
180 RTMemFree(pVScsiDevice);
181
182 return VINF_SUCCESS;;
183}
184
185
186VBOXDDU_DECL(int) VSCSIDeviceLunAttach(VSCSIDEVICE hVScsiDevice, VSCSILUN hVScsiLun, uint32_t iLun)
187{
188 PVSCSIDEVICEINT pVScsiDevice = (PVSCSIDEVICEINT)hVScsiDevice;
189 PVSCSILUNINT pVScsiLun = (PVSCSILUNINT)hVScsiLun;
190 int rc = VINF_SUCCESS;
191
192 /* Parameter checks */
193 AssertPtrReturn(pVScsiDevice, VERR_INVALID_HANDLE);
194 AssertPtrReturn(pVScsiLun, VERR_INVALID_HANDLE);
195 AssertReturn(iLun < VSCSI_DEVICE_LUN_MAX, VERR_VSCSI_LUN_INVALID);
196 AssertReturn(!pVScsiLun->pVScsiDevice, VERR_VSCSI_LUN_ATTACHED_TO_DEVICE);
197
198 if (iLun >= pVScsiDevice->cLunsMax)
199 {
200 PPVSCSILUNINT papLunOld = pVScsiDevice->papVScsiLun;
201
202 pVScsiDevice->papVScsiLun = (PPVSCSILUNINT)RTMemAllocZ((iLun + 1) * sizeof(PVSCSILUNINT));
203 if (pVScsiDevice->papVScsiLun)
204 {
205 for (uint32_t i = 0; i < pVScsiDevice->cLunsMax; i++)
206 pVScsiDevice->papVScsiLun[i] = papLunOld[i];
207
208 if (papLunOld)
209 RTMemFree(papLunOld);
210
211 pVScsiDevice->cLunsMax = iLun + 1;
212 }
213 else
214 rc = VERR_NO_MEMORY;
215 }
216
217 if (RT_SUCCESS(rc))
218 {
219 pVScsiLun->pVScsiDevice = pVScsiDevice;
220 pVScsiDevice->papVScsiLun[iLun] = pVScsiLun;
221 pVScsiDevice->cLunsAttached++;
222 }
223
224 return rc;
225}
226
227
228VBOXDDU_DECL(int) VSCSIDeviceLunDetach(VSCSIDEVICE hVScsiDevice, uint32_t iLun,
229 PVSCSILUN phVScsiLun)
230{
231 PVSCSIDEVICEINT pVScsiDevice = (PVSCSIDEVICEINT)hVScsiDevice;
232
233 /* Parameter checks */
234 AssertPtrReturn(pVScsiDevice, VERR_INVALID_HANDLE);
235 AssertPtrReturn(phVScsiLun, VERR_INVALID_POINTER);
236 AssertReturn(iLun < VSCSI_DEVICE_LUN_MAX, VERR_VSCSI_LUN_INVALID);
237 AssertReturn(iLun < pVScsiDevice->cLunsMax, VERR_VSCSI_LUN_NOT_ATTACHED);
238 AssertPtrReturn(pVScsiDevice->papVScsiLun[iLun], VERR_VSCSI_LUN_NOT_ATTACHED);
239
240 PVSCSILUNINT pVScsiLun = pVScsiDevice->papVScsiLun[iLun];
241
242 pVScsiLun->pVScsiDevice = NULL;
243 *phVScsiLun = pVScsiLun;
244 pVScsiDevice->papVScsiLun[iLun] = NULL;
245 pVScsiDevice->cLunsAttached--;
246
247 return VINF_SUCCESS;
248}
249
250
251VBOXDDU_DECL(int) VSCSIDeviceLunGet(VSCSIDEVICE hVScsiDevice, uint32_t iLun,
252 PVSCSILUN phVScsiLun)
253{
254 PVSCSIDEVICEINT pVScsiDevice = (PVSCSIDEVICEINT)hVScsiDevice;
255
256 /* Parameter checks */
257 AssertPtrReturn(pVScsiDevice, VERR_INVALID_HANDLE);
258 AssertPtrReturn(phVScsiLun, VERR_INVALID_POINTER);
259 AssertReturn(iLun < VSCSI_DEVICE_LUN_MAX, VERR_VSCSI_LUN_INVALID);
260 AssertReturn(iLun < pVScsiDevice->cLunsMax, VERR_VSCSI_LUN_NOT_ATTACHED);
261 AssertPtrReturn(pVScsiDevice->papVScsiLun[iLun], VERR_VSCSI_LUN_NOT_ATTACHED);
262
263 *phVScsiLun = pVScsiDevice->papVScsiLun[iLun];
264
265 return VINF_SUCCESS;
266}
267
268
269VBOXDDU_DECL(int) VSCSIDeviceReqEnqueue(VSCSIDEVICE hVScsiDevice, VSCSIREQ hVScsiReq)
270{
271 PVSCSIDEVICEINT pVScsiDevice = (PVSCSIDEVICEINT)hVScsiDevice;
272 PVSCSIREQINT pVScsiReq = (PVSCSIREQINT)hVScsiReq;
273 int rc = VINF_SUCCESS;
274
275 /* Parameter checks */
276 AssertPtrReturn(pVScsiDevice, VERR_INVALID_HANDLE);
277 AssertPtrReturn(pVScsiReq, VERR_INVALID_HANDLE);
278
279 /* Check if this request can be handled by us */
280 int rcReq;
281 bool fProcessed = vscsiDeviceReqProcess(pVScsiDevice, pVScsiReq, &rcReq);
282 if (!fProcessed)
283 {
284 /* Pass to the LUN driver */
285 if (vscsiDeviceLunIsPresent(pVScsiDevice, pVScsiReq->iLun))
286 {
287 PVSCSILUNINT pVScsiLun = pVScsiDevice->papVScsiLun[pVScsiReq->iLun];
288 rc = pVScsiLun->pVScsiLunDesc->pfnVScsiLunReqProcess(pVScsiLun, pVScsiReq);
289 }
290 else
291 {
292 /* LUN not present, report error. */
293 vscsiReqSenseErrorSet(&pVScsiDevice->VScsiSense, pVScsiReq,
294 SCSI_SENSE_ILLEGAL_REQUEST,
295 SCSI_ASC_LOGICAL_UNIT_DOES_NOT_RESPOND_TO_SELECTION);
296
297 vscsiDeviceReqComplete(pVScsiDevice, pVScsiReq,
298 SCSI_STATUS_CHECK_CONDITION, false, VINF_SUCCESS);
299 }
300 }
301 else
302 vscsiDeviceReqComplete(pVScsiDevice, pVScsiReq,
303 rcReq, false, VINF_SUCCESS);
304
305 return rc;
306}
307
308
309VBOXDDU_DECL(int) VSCSIDeviceReqCreate(VSCSIDEVICE hVScsiDevice, PVSCSIREQ phVScsiReq,
310 uint32_t iLun, uint8_t *pbCDB, size_t cbCDB,
311 size_t cbSGList, unsigned cSGListEntries,
312 PCRTSGSEG paSGList, uint8_t *pbSense,
313 size_t cbSense, void *pvVScsiReqUser)
314{
315 PVSCSIDEVICEINT pVScsiDevice = (PVSCSIDEVICEINT)hVScsiDevice;
316 PVSCSIREQINT pVScsiReq = NULL;
317
318 /* Parameter checks */
319 AssertPtrReturn(pVScsiDevice, VERR_INVALID_HANDLE);
320 AssertPtrReturn(phVScsiReq, VERR_INVALID_POINTER);
321 AssertPtrReturn(pbCDB, VERR_INVALID_PARAMETER);
322 AssertReturn(cbCDB > 0, VERR_INVALID_PARAMETER);
323
324 pVScsiReq = (PVSCSIREQINT)RTMemCacheAlloc(pVScsiDevice->hCacheReq);
325 if (!pVScsiReq)
326 return VERR_NO_MEMORY;
327
328 pVScsiReq->iLun = iLun;
329 pVScsiReq->pbCDB = pbCDB;
330 pVScsiReq->cbCDB = cbCDB;
331 pVScsiReq->pbSense = pbSense;
332 pVScsiReq->cbSense = cbSense;
333 pVScsiReq->pvVScsiReqUser = pvVScsiReqUser;
334
335 vscsiIoMemCtxInit(&pVScsiReq->IoMemCtx, paSGList, cSGListEntries);
336
337 *phVScsiReq = pVScsiReq;
338
339 return VINF_SUCCESS;
340}
341
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