VirtualBox

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

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

Devices/Storage/VSCSI: Add possiblity for the LUN to attach opaque data to a VSCSI request for additional book keeping

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette