VirtualBox

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

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

Devices/Storage/DrvSCSI,VSCSI: Support CD/DVD images with multiple tracks like for DevATA to bring the AHCI and SCSI controllers up to the same feature level

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.4 KB
Line 
1/* $Id: VSCSILunSbc.cpp 66955 2017-05-18 15:57:16Z vboxsync $ */
2/** @file
3 * Virtual SCSI driver: SBC LUN implementation (hard disks)
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/cdefs.h>
28#include <iprt/asm.h>
29#include <iprt/assert.h>
30#include <iprt/mem.h>
31#include <iprt/string.h>
32
33#include "VSCSIInternal.h"
34
35/** Maximum of amount of LBAs to unmap with one command. */
36#define VSCSI_UNMAP_LBAS_MAX(a_cbSector) ((10*_1M) / a_cbSector)
37
38/**
39 * SBC LUN instance
40 */
41typedef struct VSCSILUNSBC
42{
43 /** Core LUN structure */
44 VSCSILUNINT Core;
45 /** Sector size of the medium. */
46 uint64_t cbSector;
47 /** Size of the virtual disk. */
48 uint64_t cSectors;
49 /** VPD page pool. */
50 VSCSIVPDPOOL VpdPagePool;
51} VSCSILUNSBC;
52/** Pointer to a SBC LUN instance */
53typedef VSCSILUNSBC *PVSCSILUNSBC;
54
55static DECLCALLBACK(int) vscsiLunSbcInit(PVSCSILUNINT pVScsiLun)
56{
57 PVSCSILUNSBC pVScsiLunSbc = (PVSCSILUNSBC)pVScsiLun;
58 int rc = VINF_SUCCESS;
59 int cVpdPages = 0;
60
61 rc = vscsiLunMediumQueryRegionProperties(pVScsiLun, 0, NULL, &pVScsiLunSbc->cbSector,
62 &pVScsiLunSbc->cSectors, NULL);
63 if (RT_SUCCESS(rc))
64 rc = vscsiVpdPagePoolInit(&pVScsiLunSbc->VpdPagePool);
65
66 /* Create device identification page - mandatory. */
67 if (RT_SUCCESS(rc))
68 {
69 PVSCSIVPDPAGEDEVID pDevIdPage;
70
71 rc = vscsiVpdPagePoolAllocNewPage(&pVScsiLunSbc->VpdPagePool, VSCSI_VPD_DEVID_NUMBER,
72 VSCSI_VPD_DEVID_SIZE, (uint8_t **)&pDevIdPage);
73 if (RT_SUCCESS(rc))
74 {
75 /** @todo Not conforming to the SPC spec but Solaris needs at least a stub to work. */
76 pDevIdPage->u5PeripheralDeviceType = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS;
77 pDevIdPage->u3PeripheralQualifier = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_CONNECTED;
78 pDevIdPage->u16PageLength = RT_H2BE_U16(0x0);
79 cVpdPages++;
80 }
81 }
82
83 if ( RT_SUCCESS(rc)
84 && (pVScsiLun->fFeatures & VSCSI_LUN_FEATURE_UNMAP))
85 {
86 PVSCSIVPDPAGEBLOCKLIMITS pBlkPage;
87 PVSCSIVPDPAGEBLOCKPROV pBlkProvPage;
88
89 /* Create the page and fill it. */
90 rc = vscsiVpdPagePoolAllocNewPage(&pVScsiLunSbc->VpdPagePool, VSCSI_VPD_BLOCK_LIMITS_NUMBER,
91 VSCSI_VPD_BLOCK_LIMITS_SIZE, (uint8_t **)&pBlkPage);
92 if (RT_SUCCESS(rc))
93 {
94 pBlkPage->u5PeripheralDeviceType = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS;
95 pBlkPage->u3PeripheralQualifier = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_CONNECTED;
96 pBlkPage->u16PageLength = RT_H2BE_U16(0x3c);
97 pBlkPage->u8MaxCmpWriteLength = 0;
98 pBlkPage->u16OptTrfLengthGran = 0;
99 pBlkPage->u32MaxTrfLength = 0;
100 pBlkPage->u32OptTrfLength = 0;
101 pBlkPage->u32MaxPreXdTrfLength = 0;
102 pBlkPage->u32MaxUnmapLbaCount = RT_H2BE_U32(VSCSI_UNMAP_LBAS_MAX(pVScsiLunSbc->cbSector));
103 pBlkPage->u32MaxUnmapBlkDescCount = UINT32_C(0xffffffff);
104 pBlkPage->u32OptUnmapGranularity = 0;
105 pBlkPage->u32UnmapGranularityAlignment = 0;
106 cVpdPages++;
107 }
108
109 if (RT_SUCCESS(rc))
110 {
111 rc = vscsiVpdPagePoolAllocNewPage(&pVScsiLunSbc->VpdPagePool, VSCSI_VPD_BLOCK_PROV_NUMBER,
112 VSCSI_VPD_BLOCK_PROV_SIZE, (uint8_t **)&pBlkProvPage);
113 if (RT_SUCCESS(rc))
114 {
115 pBlkProvPage->u5PeripheralDeviceType = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS;
116 pBlkProvPage->u3PeripheralQualifier = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_CONNECTED;
117 pBlkProvPage->u16PageLength = RT_H2BE_U16(0x4);
118 pBlkProvPage->u8ThresholdExponent = 1;
119 pBlkProvPage->fLBPU = true;
120 cVpdPages++;
121 }
122 }
123 }
124
125 if ( RT_SUCCESS(rc)
126 && (pVScsiLun->fFeatures & VSCSI_LUN_FEATURE_NON_ROTATIONAL))
127 {
128 PVSCSIVPDPAGEBLOCKCHARACTERISTICS pBlkPage;
129
130 /* Create the page and fill it. */
131 rc = vscsiVpdPagePoolAllocNewPage(&pVScsiLunSbc->VpdPagePool, VSCSI_VPD_BLOCK_CHARACTERISTICS_NUMBER,
132 VSCSI_VPD_BLOCK_CHARACTERISTICS_SIZE, (uint8_t **)&pBlkPage);
133 if (RT_SUCCESS(rc))
134 {
135 pBlkPage->u5PeripheralDeviceType = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS;
136 pBlkPage->u3PeripheralQualifier = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_CONNECTED;
137 pBlkPage->u16PageLength = RT_H2BE_U16(0x3c);
138 pBlkPage->u16MediumRotationRate = RT_H2BE_U16(VSCSI_VPD_BLOCK_CHARACT_MEDIUM_ROTATION_RATE_NON_ROTATING);
139 cVpdPages++;
140 }
141 }
142
143 if ( RT_SUCCESS(rc)
144 && cVpdPages)
145 {
146 PVSCSIVPDPAGESUPPORTEDPAGES pVpdPages;
147
148 rc = vscsiVpdPagePoolAllocNewPage(&pVScsiLunSbc->VpdPagePool, VSCSI_VPD_SUPPORTED_PAGES_NUMBER,
149 VSCSI_VPD_SUPPORTED_PAGES_SIZE + cVpdPages, (uint8_t **)&pVpdPages);
150 if (RT_SUCCESS(rc))
151 {
152 unsigned idxVpdPage = 0;
153 pVpdPages->u5PeripheralDeviceType = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS;
154 pVpdPages->u3PeripheralQualifier = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_CONNECTED;
155 pVpdPages->u16PageLength = RT_H2BE_U16(cVpdPages);
156
157 pVpdPages->abVpdPages[idxVpdPage++] = VSCSI_VPD_DEVID_NUMBER;
158
159 if (pVScsiLun->fFeatures & VSCSI_LUN_FEATURE_UNMAP)
160 {
161 pVpdPages->abVpdPages[idxVpdPage++] = VSCSI_VPD_BLOCK_LIMITS_NUMBER;
162 pVpdPages->abVpdPages[idxVpdPage++] = VSCSI_VPD_BLOCK_PROV_NUMBER;
163 }
164
165 if (pVScsiLun->fFeatures & VSCSI_LUN_FEATURE_NON_ROTATIONAL)
166 pVpdPages->abVpdPages[idxVpdPage++] = VSCSI_VPD_BLOCK_CHARACTERISTICS_NUMBER;
167 }
168 }
169
170 /* For SBC LUNs, there will be no ready state transitions. */
171 pVScsiLunSbc->Core.fReady = true;
172
173 return rc;
174}
175
176static DECLCALLBACK(int) vscsiLunSbcDestroy(PVSCSILUNINT pVScsiLun)
177{
178 PVSCSILUNSBC pVScsiLunSbc = (PVSCSILUNSBC)pVScsiLun;
179
180 vscsiVpdPagePoolDestroy(&pVScsiLunSbc->VpdPagePool);
181
182 return VINF_SUCCESS;
183}
184
185static DECLCALLBACK(int) vscsiLunSbcReqProcess(PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq)
186{
187 PVSCSILUNSBC pVScsiLunSbc = (PVSCSILUNSBC)pVScsiLun;
188 int rc = VINF_SUCCESS;
189 int rcReq = SCSI_STATUS_OK;
190 uint64_t uLbaStart = 0;
191 uint32_t cSectorTransfer = 0;
192 VSCSIIOREQTXDIR enmTxDir = VSCSIIOREQTXDIR_INVALID;
193
194 switch(pVScsiReq->pbCDB[0])
195 {
196 case SCSI_INQUIRY:
197 {
198 vscsiReqSetXferSize(pVScsiReq, scsiBE2H_U16(&pVScsiReq->pbCDB[3]));
199
200 /* Check for EVPD bit. */
201 if (pVScsiReq->pbCDB[1] & 0x1)
202 {
203 rc = vscsiVpdPagePoolQueryPage(&pVScsiLunSbc->VpdPagePool, pVScsiReq, pVScsiReq->pbCDB[2]);
204 if (RT_UNLIKELY(rc == VERR_NOT_FOUND))
205 {
206 rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST,
207 SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
208 rc = VINF_SUCCESS;
209 }
210 else
211 rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
212 }
213 else if (pVScsiReq->pbCDB[2] != 0) /* A non zero page code is an error. */
214 rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST,
215 SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
216 else
217 {
218 SCSIINQUIRYDATA ScsiInquiryReply;
219
220 memset(&ScsiInquiryReply, 0, sizeof(ScsiInquiryReply));
221
222 ScsiInquiryReply.cbAdditional = 31;
223 ScsiInquiryReply.u5PeripheralDeviceType = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS;
224 ScsiInquiryReply.u3PeripheralQualifier = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_CONNECTED;
225 ScsiInquiryReply.u3AnsiVersion = 0x05; /* SPC-4 compliant */
226 ScsiInquiryReply.fCmdQue = 1; /* Command queuing supported. */
227 ScsiInquiryReply.fWBus16 = 1;
228 scsiPadStrS(ScsiInquiryReply.achVendorId, "VBOX", 8);
229 scsiPadStrS(ScsiInquiryReply.achProductId, "HARDDISK", 16);
230 scsiPadStrS(ScsiInquiryReply.achProductLevel, "1.0", 4);
231
232 RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, (uint8_t *)&ScsiInquiryReply, sizeof(SCSIINQUIRYDATA));
233 rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
234 }
235 break;
236 }
237 case SCSI_READ_CAPACITY:
238 {
239 uint8_t aReply[8];
240 memset(aReply, 0, sizeof(aReply));
241
242 vscsiReqSetXferSize(pVScsiReq, sizeof(aReply));
243
244 /*
245 * If sector size exceeds the maximum value that is
246 * able to be stored in 4 bytes return 0xffffffff in this field
247 */
248 if (pVScsiLunSbc->cSectors > UINT32_C(0xffffffff))
249 scsiH2BE_U32(aReply, UINT32_C(0xffffffff));
250 else
251 scsiH2BE_U32(aReply, pVScsiLunSbc->cSectors - 1);
252 scsiH2BE_U32(&aReply[4], (uint32_t)pVScsiLunSbc->cbSector);
253 RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, sizeof(aReply));
254 rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
255 break;
256 }
257 case SCSI_MODE_SENSE_6:
258 {
259 uint8_t uModePage = pVScsiReq->pbCDB[2] & 0x3f;
260 uint8_t aReply[24];
261 uint8_t *pu8ReplyPos;
262 bool fValid = false;
263
264 vscsiReqSetXferSize(pVScsiReq, pVScsiReq->pbCDB[4]);
265 memset(aReply, 0, sizeof(aReply));
266 aReply[0] = 4; /* Reply length 4. */
267 aReply[1] = 0; /* Default media type. */
268 aReply[2] = RT_BIT(4); /* Caching supported. */
269 aReply[3] = 0; /* Block descriptor length. */
270
271 if (pVScsiLun->fFeatures & VSCSI_LUN_FEATURE_READONLY)
272 aReply[2] |= RT_BIT(7); /* Set write protect bit */
273
274 pu8ReplyPos = aReply + 4;
275
276 if ((uModePage == 0x08) || (uModePage == 0x3f))
277 {
278 memset(pu8ReplyPos, 0, 20);
279 *pu8ReplyPos++ = 0x08; /* Page code. */
280 *pu8ReplyPos++ = 0x12; /* Size of the page. */
281 *pu8ReplyPos++ = 0x4; /* Write cache enabled. */
282 fValid = true;
283 } else if (uModePage == 0) {
284 fValid = true;
285 }
286
287 /* Querying unknown pages must fail. */
288 if (fValid) {
289 RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, sizeof(aReply));
290 rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
291 } else {
292 rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
293 }
294 break;
295 }
296 case SCSI_MODE_SELECT_6:
297 {
298 uint8_t abParms[12];
299 size_t cbCopied;
300 size_t cbList = pVScsiReq->pbCDB[4];
301
302 vscsiReqSetXferSize(pVScsiReq, pVScsiReq->pbCDB[4]);
303
304 /* Copy the parameters. */
305 cbCopied = RTSgBufCopyToBuf(&pVScsiReq->SgBuf, &abParms[0], sizeof(abParms));
306
307 /* Handle short LOGICAL BLOCK LENGTH parameter. */
308 if ( !(pVScsiReq->pbCDB[1] & 0x01)
309 && cbCopied == sizeof(abParms)
310 && cbList >= 12
311 && abParms[3] == 8)
312 {
313 uint32_t cbBlock;
314
315 cbBlock = scsiBE2H_U24(&abParms[4 + 5]);
316 Log2(("SBC: set LOGICAL BLOCK LENGTH to %u\n", cbBlock));
317 if (cbBlock == 512) /* Fixed block size. */
318 {
319 rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
320 break;
321 }
322 }
323 /* Fail any other requests. */
324 rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
325 break;
326 }
327 case SCSI_READ_6:
328 {
329 enmTxDir = VSCSIIOREQTXDIR_READ;
330 uLbaStart = ((uint64_t) pVScsiReq->pbCDB[3]
331 | (pVScsiReq->pbCDB[2] << 8)
332 | ((pVScsiReq->pbCDB[1] & 0x1f) << 16));
333 cSectorTransfer = pVScsiReq->pbCDB[4];
334 break;
335 }
336 case SCSI_READ_10:
337 {
338 enmTxDir = VSCSIIOREQTXDIR_READ;
339 uLbaStart = scsiBE2H_U32(&pVScsiReq->pbCDB[2]);
340 cSectorTransfer = scsiBE2H_U16(&pVScsiReq->pbCDB[7]);
341 break;
342 }
343 case SCSI_READ_12:
344 {
345 enmTxDir = VSCSIIOREQTXDIR_READ;
346 uLbaStart = scsiBE2H_U32(&pVScsiReq->pbCDB[2]);
347 cSectorTransfer = scsiBE2H_U32(&pVScsiReq->pbCDB[6]);
348 break;
349 }
350 case SCSI_READ_16:
351 {
352 enmTxDir = VSCSIIOREQTXDIR_READ;
353 uLbaStart = scsiBE2H_U64(&pVScsiReq->pbCDB[2]);
354 cSectorTransfer = scsiBE2H_U32(&pVScsiReq->pbCDB[10]);
355 break;
356 }
357 case SCSI_WRITE_6:
358 {
359 enmTxDir = VSCSIIOREQTXDIR_WRITE;
360 uLbaStart = ((uint64_t) pVScsiReq->pbCDB[3]
361 | (pVScsiReq->pbCDB[2] << 8)
362 | ((pVScsiReq->pbCDB[1] & 0x1f) << 16));
363 cSectorTransfer = pVScsiReq->pbCDB[4];
364 break;
365 }
366 case SCSI_WRITE_10:
367 {
368 enmTxDir = VSCSIIOREQTXDIR_WRITE;
369 uLbaStart = scsiBE2H_U32(&pVScsiReq->pbCDB[2]);
370 cSectorTransfer = scsiBE2H_U16(&pVScsiReq->pbCDB[7]);
371 break;
372 }
373 case SCSI_WRITE_12:
374 {
375 enmTxDir = VSCSIIOREQTXDIR_WRITE;
376 uLbaStart = scsiBE2H_U32(&pVScsiReq->pbCDB[2]);
377 cSectorTransfer = scsiBE2H_U32(&pVScsiReq->pbCDB[6]);
378 break;
379 }
380 case SCSI_WRITE_16:
381 {
382 enmTxDir = VSCSIIOREQTXDIR_WRITE;
383 uLbaStart = scsiBE2H_U64(&pVScsiReq->pbCDB[2]);
384 cSectorTransfer = scsiBE2H_U32(&pVScsiReq->pbCDB[10]);
385 break;
386 }
387 case SCSI_SYNCHRONIZE_CACHE:
388 {
389 break; /* Handled below */
390 }
391 case SCSI_READ_BUFFER:
392 {
393 uint8_t uDataMode = pVScsiReq->pbCDB[1] & 0x1f;
394
395 vscsiReqSetXferSize(pVScsiReq, scsiBE2H_U16(&pVScsiReq->pbCDB[6]));
396
397 switch (uDataMode)
398 {
399 case 0x00:
400 case 0x01:
401 case 0x02:
402 case 0x03:
403 case 0x0a:
404 break;
405 case 0x0b:
406 {
407 uint8_t aReply[4];
408
409 /* We do not implement an echo buffer. */
410 memset(aReply, 0, sizeof(aReply));
411
412 RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, sizeof(aReply));
413 rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
414 break;
415 }
416 case 0x1a:
417 case 0x1c:
418 break;
419 default:
420 AssertMsgFailed(("Invalid data mode\n"));
421 }
422 break;
423 }
424 case SCSI_VERIFY_10:
425 case SCSI_START_STOP_UNIT:
426 {
427 vscsiReqSetXferSize(pVScsiReq, 0);
428 rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
429 break;
430 }
431 case SCSI_LOG_SENSE:
432 {
433 uint8_t uPageCode = pVScsiReq->pbCDB[2] & 0x3f;
434 uint8_t uSubPageCode = pVScsiReq->pbCDB[3];
435
436 vscsiReqSetXferSize(pVScsiReq, scsiBE2H_U16(&pVScsiReq->pbCDB[7]));
437
438 switch (uPageCode)
439 {
440 case 0x00:
441 {
442 if (uSubPageCode == 0)
443 {
444 uint8_t aReply[4];
445
446 aReply[0] = 0;
447 aReply[1] = 0;
448 aReply[2] = 0;
449 aReply[3] = 0;
450 RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, sizeof(aReply));
451 rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
452 break;
453 }
454 }
455 /* fall thru */
456 default:
457 rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
458 }
459 break;
460 }
461 case SCSI_SERVICE_ACTION_IN_16:
462 {
463 switch (pVScsiReq->pbCDB[1] & 0x1f)
464 {
465 case SCSI_SVC_ACTION_IN_READ_CAPACITY_16:
466 {
467 uint8_t aReply[32];
468
469 memset(aReply, 0, sizeof(aReply));
470 scsiH2BE_U64(aReply, pVScsiLunSbc->cSectors - 1);
471 scsiH2BE_U32(&aReply[8], 512);
472 if (pVScsiLun->fFeatures & VSCSI_LUN_FEATURE_UNMAP)
473 aReply[14] = 0x80; /* LPME enabled */
474 /* Leave the rest 0 */
475
476 vscsiReqSetXferSize(pVScsiReq, sizeof(aReply));
477 RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, sizeof(aReply));
478 rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
479 break;
480 }
481 default:
482 rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00); /* Don't know if this is correct */
483 }
484 break;
485 }
486 case SCSI_UNMAP:
487 {
488 if (pVScsiLun->fFeatures & VSCSI_LUN_FEATURE_UNMAP)
489 {
490 uint8_t abHdr[8];
491 size_t cbCopied;
492 size_t cbList = scsiBE2H_U16(&pVScsiReq->pbCDB[7]);
493
494 /* Copy the header. */
495 vscsiReqSetXferSize(pVScsiReq, cbList);
496 cbCopied = RTSgBufCopyToBuf(&pVScsiReq->SgBuf, &abHdr[0], sizeof(abHdr));
497
498 /* Using the anchor bit is not supported. */
499 if ( !(pVScsiReq->pbCDB[1] & 0x01)
500 && cbCopied == sizeof(abHdr)
501 && cbList >= 8)
502 {
503 uint32_t cBlkDesc = scsiBE2H_U16(&abHdr[2]) / 16;
504
505 if (cBlkDesc)
506 {
507 PRTRANGE paRanges = (PRTRANGE)RTMemAllocZ(cBlkDesc * sizeof(RTRANGE));
508 if (paRanges)
509 {
510 for (unsigned i = 0; i < cBlkDesc; i++)
511 {
512 uint8_t abBlkDesc[16];
513
514 cbCopied = RTSgBufCopyToBuf(&pVScsiReq->SgBuf, &abBlkDesc[0], sizeof(abBlkDesc));
515 if (RT_UNLIKELY(cbCopied != sizeof(abBlkDesc)))
516 {
517 rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
518 break;
519 }
520
521 paRanges[i].offStart = scsiBE2H_U64(&abBlkDesc[0]) * 512;
522 paRanges[i].cbRange = scsiBE2H_U32(&abBlkDesc[8]) * 512;
523 }
524
525 if (rcReq == SCSI_STATUS_OK)
526 rc = vscsiIoReqUnmapEnqueue(pVScsiLun, pVScsiReq, paRanges, cBlkDesc);
527 if ( rcReq != SCSI_STATUS_OK
528 || RT_FAILURE(rc))
529 RTMemFree(paRanges);
530 }
531 else /* Out of memory. */
532 rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_HARDWARE_ERROR, SCSI_ASC_SYSTEM_RESOURCE_FAILURE,
533 SCSI_ASCQ_SYSTEM_BUFFER_FULL);
534 }
535 else /* No block descriptors is not an error condition. */
536 rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
537 }
538 else /* Invalid CDB. */
539 rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
540 }
541 else
542 rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE, 0x00);
543
544 break;
545 }
546 default:
547 //AssertMsgFailed(("Command %#x [%s] not implemented\n", pRequest->pbCDB[0], SCSICmdText(pRequest->pbCDB[0])));
548 rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE, 0x00);
549 }
550
551 if (enmTxDir != VSCSIIOREQTXDIR_INVALID)
552 {
553 LogFlow(("%s: uLbaStart=%llu cSectorTransfer=%u\n",
554 __FUNCTION__, uLbaStart, cSectorTransfer));
555
556 vscsiReqSetXferSize(pVScsiReq, cSectorTransfer * 512);
557
558 if (RT_UNLIKELY(uLbaStart + cSectorTransfer > pVScsiLunSbc->cSectors))
559 {
560 rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR, 0x00);
561 vscsiDeviceReqComplete(pVScsiLun->pVScsiDevice, pVScsiReq, rcReq, false, VINF_SUCCESS);
562 }
563 else if (!cSectorTransfer)
564 {
565 /* A 0 transfer length is not an error. */
566 rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
567 vscsiDeviceReqComplete(pVScsiLun->pVScsiDevice, pVScsiReq, rcReq, false, VINF_SUCCESS);
568 }
569 else
570 {
571 /* Enqueue new I/O request */
572 if ( ( enmTxDir == VSCSIIOREQTXDIR_WRITE
573 || enmTxDir == VSCSIIOREQTXDIR_FLUSH)
574 && (pVScsiLun->fFeatures & VSCSI_LUN_FEATURE_READONLY))
575 rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_DATA_PROTECT, SCSI_ASC_WRITE_PROTECTED, 0x00);
576 else
577 rc = vscsiIoReqTransferEnqueue(pVScsiLun, pVScsiReq, enmTxDir,
578 uLbaStart * 512, cSectorTransfer * 512);
579 }
580 }
581 else if (pVScsiReq->pbCDB[0] == SCSI_SYNCHRONIZE_CACHE)
582 {
583 /* Enqueue flush */
584 vscsiReqSetXferSize(pVScsiReq, 0);
585 rc = vscsiIoReqFlushEnqueue(pVScsiLun, pVScsiReq);
586 }
587 else if (pVScsiReq->pbCDB[0] != SCSI_UNMAP) /* Request completed */
588 vscsiDeviceReqComplete(pVScsiLun->pVScsiDevice, pVScsiReq, rcReq, false, VINF_SUCCESS);
589
590 return rc;
591}
592
593VSCSILUNDESC g_VScsiLunTypeSbc =
594{
595 /** enmLunType */
596 VSCSILUNTYPE_SBC,
597 /** pcszDescName */
598 "SBC",
599 /** cbLun */
600 sizeof(VSCSILUNSBC),
601 /** cSupOpcInfo */
602 0,
603 /** paSupOpcInfo */
604 NULL,
605 /** pfnVScsiLunInit */
606 vscsiLunSbcInit,
607 /** pfnVScsiLunDestroy */
608 vscsiLunSbcDestroy,
609 /** pfnVScsiLunReqProcess */
610 vscsiLunSbcReqProcess,
611 /** pfnVScsiLunReqFree */
612 NULL,
613 /** pfnVScsiLunMediumInserted */
614 NULL,
615 /** pfnVScsiLunMediumRemoved */
616 NULL
617};
618
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