VirtualBox

source: vbox/trunk/src/VBox/Devices/Storage/VSCSI/VSCSILunSbc.cpp@ 38678

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

VSCSI: Replace I/O memory context with S/G buffers

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.7 KB
Line 
1/* $Id: VSCSILunSbc.cpp 38678 2011-09-07 17:33:13Z vboxsync $ */
2/** @file
3 * Virtual SCSI driver: SBC LUN implementation (hard disks)
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
18/*******************************************************************************
19* Header Files *
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 * SBC LUN instance
34 */
35typedef struct VSCSILUNSBC
36{
37 /** Core LUN structure */
38 VSCSILUNINT Core;
39 /** Size of the virtual disk. */
40 uint64_t cSectors;
41} VSCSILUNSBC;
42/** Pointer to a SBC LUN instance */
43typedef VSCSILUNSBC *PVSCSILUNSBC;
44
45static int vscsiLunSbcInit(PVSCSILUNINT pVScsiLun)
46{
47 PVSCSILUNSBC pVScsiLunSbc = (PVSCSILUNSBC)pVScsiLun;
48 uint64_t cbDisk = 0;
49 int rc = VINF_SUCCESS;
50
51 rc = vscsiLunMediumGetSize(pVScsiLun, &cbDisk);
52 if (RT_SUCCESS(rc))
53 pVScsiLunSbc->cSectors = cbDisk / 512; /* Fixed sector size */
54
55 return rc;
56}
57
58static int vscsiLunSbcDestroy(PVSCSILUNINT pVScsiLun)
59{
60 PVSCSILUNSBC pVScsiLunSbc = (PVSCSILUNSBC)pVScsiLun;
61
62 return VINF_SUCCESS;
63}
64
65static int vscsiLunSbcReqProcess(PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq)
66{
67 PVSCSILUNSBC pVScsiLunSbc = (PVSCSILUNSBC)pVScsiLun;
68 int rc = VINF_SUCCESS;
69 int rcReq = SCSI_STATUS_OK;
70 uint64_t uLbaStart = 0;
71 uint32_t cSectorTransfer = 0;
72 VSCSIIOREQTXDIR enmTxDir = VSCSIIOREQTXDIR_INVALID;
73
74 switch(pVScsiReq->pbCDB[0])
75 {
76 case SCSI_INQUIRY:
77 {
78 SCSIINQUIRYDATA ScsiInquiryReply;
79
80 memset(&ScsiInquiryReply, 0, sizeof(ScsiInquiryReply));
81
82 ScsiInquiryReply.cbAdditional = 31;
83 ScsiInquiryReply.u5PeripheralDeviceType = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS;
84 ScsiInquiryReply.u3PeripheralQualifier = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_CONNECTED;
85 ScsiInquiryReply.u3AnsiVersion = 0x05; /* SPC-4 compliant */
86 ScsiInquiryReply.fCmdQue = 1; /* Command queuing supported. */
87 ScsiInquiryReply.fWBus16 = 1;
88 vscsiPadStr(ScsiInquiryReply.achVendorId, "VBOX", 8);
89 vscsiPadStr(ScsiInquiryReply.achProductId, "HARDDISK", 16);
90 vscsiPadStr(ScsiInquiryReply.achProductLevel, "1.0", 4);
91
92 RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, (uint8_t *)&ScsiInquiryReply, sizeof(SCSIINQUIRYDATA));
93 rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
94 break;
95 }
96 case SCSI_READ_CAPACITY:
97 {
98 uint8_t aReply[8];
99 memset(aReply, 0, sizeof(aReply));
100
101 /*
102 * If sector size exceeds the maximum value that is
103 * able to be stored in 4 bytes return 0xffffffff in this field
104 */
105 if (pVScsiLunSbc->cSectors > UINT32_C(0xffffffff))
106 vscsiH2BEU32(aReply, UINT32_C(0xffffffff));
107 else
108 vscsiH2BEU32(aReply, pVScsiLunSbc->cSectors - 1);
109 vscsiH2BEU32(&aReply[4], 512);
110 RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, sizeof(aReply));
111 rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
112 break;
113 }
114 case SCSI_MODE_SENSE_6:
115 {
116 uint8_t uModePage = pVScsiReq->pbCDB[2] & 0x3f;
117 uint8_t aReply[24];
118 uint8_t *pu8ReplyPos;
119
120 memset(aReply, 0, sizeof(aReply));
121 aReply[0] = 4; /* Reply length 4. */
122 aReply[1] = 0; /* Default media type. */
123 aReply[2] = RT_BIT(4); /* Caching supported. */
124 aReply[3] = 0; /* Block descriptor length. */
125
126 pu8ReplyPos = aReply + 4;
127
128 if ((uModePage == 0x08) || (uModePage == 0x3f))
129 {
130 memset(pu8ReplyPos, 0, 20);
131 *pu8ReplyPos++ = 0x08; /* Page code. */
132 *pu8ReplyPos++ = 0x12; /* Size of the page. */
133 *pu8ReplyPos++ = 0x4; /* Write cache enabled. */
134 }
135
136 RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, sizeof(aReply));
137 rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
138 break;
139 }
140 case SCSI_READ_6:
141 {
142 enmTxDir = VSCSIIOREQTXDIR_READ;
143 uLbaStart = ((uint64_t) pVScsiReq->pbCDB[3]
144 | (pVScsiReq->pbCDB[2] << 8)
145 | ((pVScsiReq->pbCDB[1] & 0x1f) << 16));
146 cSectorTransfer = pVScsiReq->pbCDB[4];
147 break;
148 }
149 case SCSI_READ_10:
150 {
151 enmTxDir = VSCSIIOREQTXDIR_READ;
152 uLbaStart = vscsiBE2HU32(&pVScsiReq->pbCDB[2]);
153 cSectorTransfer = vscsiBE2HU16(&pVScsiReq->pbCDB[7]);
154 break;
155 }
156 case SCSI_READ_12:
157 {
158 enmTxDir = VSCSIIOREQTXDIR_READ;
159 uLbaStart = vscsiBE2HU32(&pVScsiReq->pbCDB[2]);
160 cSectorTransfer = vscsiBE2HU32(&pVScsiReq->pbCDB[6]);
161 break;
162 }
163 case SCSI_READ_16:
164 {
165 enmTxDir = VSCSIIOREQTXDIR_READ;
166 uLbaStart = vscsiBE2HU64(&pVScsiReq->pbCDB[2]);
167 cSectorTransfer = vscsiBE2HU32(&pVScsiReq->pbCDB[10]);
168 break;
169 }
170 case SCSI_WRITE_6:
171 {
172 enmTxDir = VSCSIIOREQTXDIR_WRITE;
173 uLbaStart = ((uint64_t) pVScsiReq->pbCDB[3]
174 | (pVScsiReq->pbCDB[2] << 8)
175 | ((pVScsiReq->pbCDB[1] & 0x1f) << 16));
176 cSectorTransfer = pVScsiReq->pbCDB[4];
177 break;
178 }
179 case SCSI_WRITE_10:
180 {
181 enmTxDir = VSCSIIOREQTXDIR_WRITE;
182 uLbaStart = vscsiBE2HU32(&pVScsiReq->pbCDB[2]);
183 cSectorTransfer = vscsiBE2HU16(&pVScsiReq->pbCDB[7]);
184 break;
185 }
186 case SCSI_WRITE_12:
187 {
188 enmTxDir = VSCSIIOREQTXDIR_WRITE;
189 uLbaStart = vscsiBE2HU32(&pVScsiReq->pbCDB[2]);
190 cSectorTransfer = vscsiBE2HU32(&pVScsiReq->pbCDB[6]);
191 break;
192 }
193 case SCSI_WRITE_16:
194 {
195 enmTxDir = VSCSIIOREQTXDIR_WRITE;
196 uLbaStart = vscsiBE2HU64(&pVScsiReq->pbCDB[2]);
197 cSectorTransfer = vscsiBE2HU32(&pVScsiReq->pbCDB[10]);
198 break;
199 }
200 case SCSI_SYNCHRONIZE_CACHE:
201 {
202 break; /* Handled below */
203 }
204 case SCSI_READ_BUFFER:
205 {
206 uint8_t uDataMode = pVScsiReq->pbCDB[1] & 0x1f;
207
208 switch (uDataMode)
209 {
210 case 0x00:
211 case 0x01:
212 case 0x02:
213 case 0x03:
214 case 0x0a:
215 break;
216 case 0x0b:
217 {
218 uint8_t aReply[4];
219
220 /* We do not implement an echo buffer. */
221 memset(aReply, 0, sizeof(aReply));
222
223 RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, sizeof(aReply));
224 rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
225 break;
226 }
227 case 0x1a:
228 case 0x1c:
229 break;
230 default:
231 AssertMsgFailed(("Invalid data mode\n"));
232 }
233 break;
234 }
235 case SCSI_VERIFY_10:
236 case SCSI_START_STOP_UNIT:
237 {
238 rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
239 break;
240 }
241 case SCSI_LOG_SENSE:
242 {
243 uint16_t cbMax = vscsiBE2HU16(&pVScsiReq->pbCDB[7]);
244 uint8_t uPageCode = pVScsiReq->pbCDB[2] & 0x3f;
245 uint8_t uSubPageCode = pVScsiReq->pbCDB[3];
246
247 switch (uPageCode)
248 {
249 case 0x00:
250 {
251 if (uSubPageCode == 0)
252 {
253 uint8_t aReply[4];
254
255 aReply[0] = 0;
256 aReply[1] = 0;
257 aReply[2] = 0;
258 aReply[3] = 0;
259 RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, sizeof(aReply));
260 rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
261 break;
262 }
263 }
264 default:
265 rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
266 }
267 break;
268 }
269 case SCSI_SERVICE_ACTION_IN_16:
270 {
271 switch (pVScsiReq->pbCDB[1] & 0x1f)
272 {
273 case SCSI_SVC_ACTION_IN_READ_CAPACITY_16:
274 {
275 uint8_t aReply[32];
276
277 memset(aReply, 0, sizeof(aReply));
278 vscsiH2BEU64(aReply, pVScsiLunSbc->cSectors - 1);
279 vscsiH2BEU32(&aReply[8], 512);
280 /* Leave the rest 0 */
281
282 RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, sizeof(aReply));
283 rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
284 break;
285 }
286 default:
287 rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET); /* Don't know if this is correct */
288 }
289 break;
290 }
291 default:
292 //AssertMsgFailed(("Command %#x [%s] not implemented\n", pRequest->pbCDB[0], SCSICmdText(pRequest->pbCDB[0])));
293 rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
294 }
295
296 if (enmTxDir != VSCSIIOREQTXDIR_INVALID)
297 {
298 LogFlow(("%s: uLbaStart=%llu cSectorTransfer=%u\n",
299 __FUNCTION__, uLbaStart, cSectorTransfer));
300
301 if (RT_UNLIKELY(uLbaStart + cSectorTransfer > pVScsiLunSbc->cSectors))
302 {
303 rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
304 vscsiDeviceReqComplete(pVScsiLun->pVScsiDevice, pVScsiReq, rcReq, false, VINF_SUCCESS);
305 }
306 else
307 {
308 /* Enqueue new I/O request */
309 rc = vscsiIoReqTransferEnqueue(pVScsiLun, pVScsiReq, enmTxDir,
310 uLbaStart * 512, cSectorTransfer * 512);
311 }
312 }
313 else if (pVScsiReq->pbCDB[0] == SCSI_SYNCHRONIZE_CACHE)
314 {
315 /* Enqueue flush */
316 rc = vscsiIoReqFlushEnqueue(pVScsiLun, pVScsiReq);
317 }
318 else /* Request completed */
319 vscsiDeviceReqComplete(pVScsiLun->pVScsiDevice, pVScsiReq, rcReq, false, VINF_SUCCESS);
320
321 return rc;
322}
323
324VSCSILUNDESC g_VScsiLunTypeSbc =
325{
326 /** enmLunType */
327 VSCSILUNTYPE_SBC,
328 /** pcszDescName */
329 "SBC",
330 /** cbLun */
331 sizeof(VSCSILUNSBC),
332 /** pfnVScsiLunInit */
333 vscsiLunSbcInit,
334 /** pfnVScsiLunDestroy */
335 vscsiLunSbcDestroy,
336 /** pfnVScsiLunReqProcess */
337 vscsiLunSbcReqProcess
338};
339
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