VirtualBox

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

Last change on this file since 28125 was 28065, checked in by vboxsync, 15 years ago

Storage: Convert from PDMDATASEG to RTSGSEG to avoid casting between those two in VBoxHDD and more async I/O updates

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