VirtualBox

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

Last change on this file since 56690 was 56292, checked in by vboxsync, 10 years ago

Devices: Updated (C) year.

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