VirtualBox

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

Last change on this file since 32983 was 32983, checked in by vboxsync, 14 years ago

LsiLogic: Suspend the VM on a recoverable error without changing the saved state format

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.2 KB
Line 
1/* $Id: VSCSIDevice.cpp 32983 2010-10-07 15:14:54Z 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(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(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(pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
94 else
95 *prcReq = vscsiReqSenseOkSet(pVScsiReq);
96 }
97 break;
98 }
99 case SCSI_TEST_UNIT_READY:
100 {
101 *prcReq = vscsiReqSenseOkSet(pVScsiReq);
102 break;
103 }
104 default:
105 fProcessed = false;
106 }
107
108 return fProcessed;
109}
110
111
112void vscsiDeviceReqComplete(PVSCSIDEVICEINT pVScsiDevice, PVSCSIREQINT pVScsiReq,
113 int rcScsiCode, bool fRedoPossible, int rcReq)
114{
115 pVScsiDevice->pfnVScsiReqCompleted(pVScsiDevice, pVScsiDevice->pvVScsiDeviceUser,
116 pVScsiReq->pvVScsiReqUser, rcScsiCode, fRedoPossible,
117 rcReq);
118
119 RTMemCacheFree(pVScsiDevice->hCacheReq, pVScsiReq);
120}
121
122
123VBOXDDU_DECL(int) VSCSIDeviceCreate(PVSCSIDEVICE phVScsiDevice,
124 PFNVSCSIREQCOMPLETED pfnVScsiReqCompleted,
125 void *pvVScsiDeviceUser)
126{
127 int rc = VINF_SUCCESS;
128 PVSCSIDEVICEINT pVScsiDevice = NULL;
129
130 AssertPtrReturn(phVScsiDevice, VERR_INVALID_POINTER);
131 AssertPtrReturn(pfnVScsiReqCompleted, VERR_INVALID_POINTER);
132
133 pVScsiDevice = (PVSCSIDEVICEINT)RTMemAllocZ(sizeof(VSCSIDEVICEINT));
134 if (!pVScsiDevice)
135 return VERR_NO_MEMORY;
136
137 pVScsiDevice->pfnVScsiReqCompleted = pfnVScsiReqCompleted;
138 pVScsiDevice->pvVScsiDeviceUser = pvVScsiDeviceUser;
139 pVScsiDevice->cLunsAttached = 0;
140 pVScsiDevice->cLunsMax = 0;
141 pVScsiDevice->papVScsiLun = NULL;
142
143 rc = RTMemCacheCreate(&pVScsiDevice->hCacheReq, sizeof(VSCSIREQINT), 0, UINT32_MAX,
144 NULL, NULL, NULL, 0);
145 if (RT_SUCCESS(rc))
146 {
147 *phVScsiDevice = pVScsiDevice;
148 LogFlow(("%s: hVScsiDevice=%#p -> VINF_SUCCESS\n", __FUNCTION__, pVScsiDevice));
149 return VINF_SUCCESS;
150 }
151
152 RTMemFree(pVScsiDevice);
153
154 return rc;
155}
156
157
158VBOXDDU_DECL(int) VSCSIDeviceDestroy(VSCSIDEVICE hVScsiDevice)
159{
160 AssertPtrReturn(hVScsiDevice, VERR_INVALID_HANDLE);
161
162 PVSCSIDEVICEINT pVScsiDevice = (PVSCSIDEVICEINT)hVScsiDevice;
163
164 if (pVScsiDevice->cLunsAttached > 0)
165 return VERR_VSCSI_LUN_ATTACHED_TO_DEVICE;
166
167 if (pVScsiDevice->papVScsiLun)
168 RTMemFree(pVScsiDevice->papVScsiLun);
169
170 RTMemCacheDestroy(pVScsiDevice->hCacheReq);
171 RTMemFree(pVScsiDevice);
172
173 return VINF_SUCCESS;;
174}
175
176
177VBOXDDU_DECL(int) VSCSIDeviceLunAttach(VSCSIDEVICE hVScsiDevice, VSCSILUN hVScsiLun, uint32_t iLun)
178{
179 PVSCSIDEVICEINT pVScsiDevice = (PVSCSIDEVICEINT)hVScsiDevice;
180 PVSCSILUNINT pVScsiLun = (PVSCSILUNINT)hVScsiLun;
181 int rc = VINF_SUCCESS;
182
183 /* Parameter checks */
184 AssertPtrReturn(pVScsiDevice, VERR_INVALID_HANDLE);
185 AssertPtrReturn(pVScsiLun, VERR_INVALID_HANDLE);
186 AssertReturn(iLun < VSCSI_DEVICE_LUN_MAX, VERR_VSCSI_LUN_INVALID);
187 AssertReturn(!pVScsiLun->pVScsiDevice, VERR_VSCSI_LUN_ATTACHED_TO_DEVICE);
188
189 if (iLun >= pVScsiDevice->cLunsMax)
190 {
191 PPVSCSILUNINT papLunOld = pVScsiDevice->papVScsiLun;
192
193 pVScsiDevice->papVScsiLun = (PPVSCSILUNINT)RTMemAllocZ((iLun + 1) * sizeof(PVSCSILUNINT));
194 if (pVScsiDevice->papVScsiLun)
195 {
196 for (uint32_t i = 0; i < pVScsiDevice->cLunsMax; i++)
197 pVScsiDevice->papVScsiLun[i] = papLunOld[i];
198
199 if (papLunOld)
200 RTMemFree(papLunOld);
201
202 pVScsiDevice->cLunsMax = iLun + 1;
203 }
204 else
205 rc = VERR_NO_MEMORY;
206 }
207
208 if (RT_SUCCESS(rc))
209 {
210 pVScsiLun->pVScsiDevice = pVScsiDevice;
211 pVScsiDevice->papVScsiLun[iLun] = pVScsiLun;
212 pVScsiDevice->cLunsAttached++;
213 }
214
215 return rc;
216}
217
218
219VBOXDDU_DECL(int) VSCSIDeviceLunDetach(VSCSIDEVICE hVScsiDevice, uint32_t iLun,
220 PVSCSILUN phVScsiLun)
221{
222 PVSCSIDEVICEINT pVScsiDevice = (PVSCSIDEVICEINT)hVScsiDevice;
223
224 /* Parameter checks */
225 AssertPtrReturn(pVScsiDevice, VERR_INVALID_HANDLE);
226 AssertPtrReturn(phVScsiLun, VERR_INVALID_POINTER);
227 AssertReturn(iLun < VSCSI_DEVICE_LUN_MAX, VERR_VSCSI_LUN_INVALID);
228 AssertReturn(iLun < pVScsiDevice->cLunsMax, VERR_VSCSI_LUN_NOT_ATTACHED);
229 AssertPtrReturn(pVScsiDevice->papVScsiLun[iLun], VERR_VSCSI_LUN_NOT_ATTACHED);
230
231 PVSCSILUNINT pVScsiLun = pVScsiDevice->papVScsiLun[iLun];
232
233 pVScsiLun->pVScsiDevice = NULL;
234 *phVScsiLun = pVScsiLun;
235 pVScsiDevice->papVScsiLun[iLun] = NULL;
236 pVScsiDevice->cLunsAttached--;
237
238 return VINF_SUCCESS;
239}
240
241
242VBOXDDU_DECL(int) VSCSIDeviceLunGet(VSCSIDEVICE hVScsiDevice, uint32_t iLun,
243 PVSCSILUN phVScsiLun)
244{
245 PVSCSIDEVICEINT pVScsiDevice = (PVSCSIDEVICEINT)hVScsiDevice;
246
247 /* Parameter checks */
248 AssertPtrReturn(pVScsiDevice, VERR_INVALID_HANDLE);
249 AssertPtrReturn(phVScsiLun, VERR_INVALID_POINTER);
250 AssertReturn(iLun < VSCSI_DEVICE_LUN_MAX, VERR_VSCSI_LUN_INVALID);
251 AssertReturn(iLun < pVScsiDevice->cLunsMax, VERR_VSCSI_LUN_NOT_ATTACHED);
252 AssertPtrReturn(pVScsiDevice->papVScsiLun[iLun], VERR_VSCSI_LUN_NOT_ATTACHED);
253
254 *phVScsiLun = pVScsiDevice->papVScsiLun[iLun];
255
256 return VINF_SUCCESS;
257}
258
259
260VBOXDDU_DECL(int) VSCSIDeviceReqEnqueue(VSCSIDEVICE hVScsiDevice, VSCSIREQ hVScsiReq)
261{
262 PVSCSIDEVICEINT pVScsiDevice = (PVSCSIDEVICEINT)hVScsiDevice;
263 PVSCSIREQINT pVScsiReq = (PVSCSIREQINT)hVScsiReq;
264 int rc = VINF_SUCCESS;
265
266 /* Parameter checks */
267 AssertPtrReturn(pVScsiDevice, VERR_INVALID_HANDLE);
268 AssertPtrReturn(pVScsiReq, VERR_INVALID_HANDLE);
269
270 /* Check if this request can be handled by us */
271 int rcReq;
272 bool fProcessed = vscsiDeviceReqProcess(pVScsiDevice, pVScsiReq, &rcReq);
273 if (!fProcessed)
274 {
275 /* Pass to the LUN driver */
276 if (vscsiDeviceLunIsPresent(pVScsiDevice, pVScsiReq->iLun))
277 {
278 PVSCSILUNINT pVScsiLun = pVScsiDevice->papVScsiLun[pVScsiReq->iLun];
279 rc = pVScsiLun->pVScsiLunDesc->pfnVScsiLunReqProcess(pVScsiLun, pVScsiReq);
280 }
281 else
282 {
283 /* LUN not present, report error. */
284 vscsiReqSenseErrorSet(pVScsiReq,
285 SCSI_SENSE_ILLEGAL_REQUEST,
286 SCSI_ASC_LOGICAL_UNIT_DOES_NOT_RESPOND_TO_SELECTION);
287
288 vscsiDeviceReqComplete(pVScsiDevice, pVScsiReq,
289 SCSI_STATUS_CHECK_CONDITION, false, VINF_SUCCESS);
290 }
291 }
292 else
293 vscsiDeviceReqComplete(pVScsiDevice, pVScsiReq,
294 rcReq, false, VINF_SUCCESS);
295
296 return rc;
297}
298
299
300VBOXDDU_DECL(int) VSCSIDeviceReqCreate(VSCSIDEVICE hVScsiDevice, PVSCSIREQ phVScsiReq,
301 uint32_t iLun, uint8_t *pbCDB, size_t cbCDB,
302 size_t cbSGList, unsigned cSGListEntries,
303 PCRTSGSEG paSGList, uint8_t *pbSense,
304 size_t cbSense, void *pvVScsiReqUser)
305{
306 PVSCSIDEVICEINT pVScsiDevice = (PVSCSIDEVICEINT)hVScsiDevice;
307 PVSCSIREQINT pVScsiReq = NULL;
308
309 /* Parameter checks */
310 AssertPtrReturn(pVScsiDevice, VERR_INVALID_HANDLE);
311 AssertPtrReturn(phVScsiReq, VERR_INVALID_POINTER);
312 AssertPtrReturn(pbCDB, VERR_INVALID_PARAMETER);
313 AssertReturn(cbCDB > 0, VERR_INVALID_PARAMETER);
314
315 pVScsiReq = (PVSCSIREQINT)RTMemCacheAlloc(pVScsiDevice->hCacheReq);
316 if (!pVScsiReq)
317 return VERR_NO_MEMORY;
318
319 pVScsiReq->iLun = iLun;
320 pVScsiReq->pbCDB = pbCDB;
321 pVScsiReq->cbCDB = cbCDB;
322 pVScsiReq->pbSense = pbSense;
323 pVScsiReq->cbSense = cbSense;
324 pVScsiReq->pvVScsiReqUser = pvVScsiReqUser;
325
326 vscsiIoMemCtxInit(&pVScsiReq->IoMemCtx, paSGList, cSGListEntries);
327
328 *phVScsiReq = pVScsiReq;
329
330 return VINF_SUCCESS;
331}
332
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