VirtualBox

source: vbox/trunk/src/VBox/Devices/Storage/DrvHostBase-freebsd.cpp@ 64278

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

Devices/Storage/DrvHost*: Move more host dependent code into the host specific source files, move validating the CFGM values into DRVHostBaseInitData() because it doesn't make much sense to check for unknown values after most of the values were already queried

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.9 KB
Line 
1/* $Id: DrvHostBase-freebsd.cpp 64278 2016-10-14 12:17:45Z vboxsync $ */
2/** @file
3 * DrvHostBase - Host base drive access driver, FreeBSD specifics.
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#define LOG_GROUP LOG_GROUP_DRV_HOST_BASE
18#include <sys/cdefs.h>
19#include <sys/param.h>
20#include <errno.h>
21#include <stdio.h>
22#include <cam/cam.h>
23#include <cam/cam_ccb.h>
24#include <cam/scsi/scsi_message.h>
25#include <cam/scsi/scsi_pass.h>
26#include <VBox/scsi.h>
27#include <iprt/log.h>
28
29#include "DrvHostBase.h"
30
31
32DECLHIDDEN(int) drvHostBaseScsiCmdOs(PDRVHOSTBASE pThis, const uint8_t *pbCmd, size_t cbCmd, PDMMEDIATXDIR enmTxDir,
33 void *pvBuf, uint32_t *pcbBuf, uint8_t *pbSense, size_t cbSense, uint32_t cTimeoutMillies)
34{
35 /*
36 * Minimal input validation.
37 */
38 Assert(enmTxDir == PDMMEDIATXDIR_NONE || enmTxDir == PDMMEDIATXDIR_FROM_DEVICE || enmTxDir == PDMMEDIATXDIR_TO_DEVICE);
39 Assert(!pvBuf || pcbBuf);
40 Assert(pvBuf || enmTxDir == PDMMEDIATXDIR_NONE);
41 Assert(pbSense || !cbSense);
42 AssertPtr(pbCmd);
43 Assert(cbCmd <= 16 && cbCmd >= 1);
44 const uint32_t cbBuf = pcbBuf ? *pcbBuf : 0;
45 if (pcbBuf)
46 *pcbBuf = 0;
47
48 Assert(pThis->ppScsiTaskDI);
49
50 int rc = VERR_GENERAL_FAILURE;
51 SCSITaskInterface **ppScsiTaskI = (*pThis->ppScsiTaskDI)->CreateSCSITask(pThis->ppScsiTaskDI);
52 if (!ppScsiTaskI)
53 return VERR_NO_MEMORY;
54 do
55 {
56 /* Setup the scsi command. */
57 SCSICommandDescriptorBlock cdb = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
58 memcpy(&cdb[0], pbCmd, cbCmd);
59 IOReturn irc = (*ppScsiTaskI)->SetCommandDescriptorBlock(ppScsiTaskI, cdb, cbCmd);
60 AssertBreak(irc == kIOReturnSuccess);
61
62 /* Setup the buffer. */
63 if (enmTxDir == PDMMEDIATXDIR_NONE)
64 irc = (*ppScsiTaskI)->SetScatterGatherEntries(ppScsiTaskI, NULL, 0, 0, kSCSIDataTransfer_NoDataTransfer);
65 else
66 {
67 IOVirtualRange Range = { (IOVirtualAddress)pvBuf, cbBuf };
68 irc = (*ppScsiTaskI)->SetScatterGatherEntries(ppScsiTaskI, &Range, 1, cbBuf,
69 enmTxDir == PDMMEDIATXDIR_FROM_DEVICE
70 ? kSCSIDataTransfer_FromTargetToInitiator
71 : kSCSIDataTransfer_FromInitiatorToTarget);
72 }
73 AssertBreak(irc == kIOReturnSuccess);
74
75 /* Set the timeout. */
76 irc = (*ppScsiTaskI)->SetTimeoutDuration(ppScsiTaskI, cTimeoutMillies ? cTimeoutMillies : 30000 /*ms*/);
77 AssertBreak(irc == kIOReturnSuccess);
78
79 /* Execute the command and get the response. */
80 SCSI_Sense_Data SenseData = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
81 SCSIServiceResponse ServiceResponse = kSCSIServiceResponse_Request_In_Process;
82 SCSITaskStatus TaskStatus = kSCSITaskStatus_GOOD;
83 UInt64 cbReturned = 0;
84 irc = (*ppScsiTaskI)->ExecuteTaskSync(ppScsiTaskI, &SenseData, &TaskStatus, &cbReturned);
85 AssertBreak(irc == kIOReturnSuccess);
86 if (pcbBuf)
87 *pcbBuf = (int32_t)cbReturned;
88
89 irc = (*ppScsiTaskI)->GetSCSIServiceResponse(ppScsiTaskI, &ServiceResponse);
90 AssertBreak(irc == kIOReturnSuccess);
91 AssertBreak(ServiceResponse == kSCSIServiceResponse_TASK_COMPLETE);
92
93 if (TaskStatus == kSCSITaskStatus_GOOD)
94 rc = VINF_SUCCESS;
95 else if ( TaskStatus == kSCSITaskStatus_CHECK_CONDITION
96 && pbSense)
97 {
98 memset(pbSense, 0, cbSense); /* lazy */
99 memcpy(pbSense, &SenseData, RT_MIN(sizeof(SenseData), cbSense));
100 rc = VERR_UNRESOLVED_ERROR;
101 }
102 /** @todo convert sense codes when caller doesn't wish to do this himself. */
103 /*else if ( TaskStatus == kSCSITaskStatus_CHECK_CONDITION
104 && SenseData.ADDITIONAL_SENSE_CODE == 0x3A)
105 rc = VERR_MEDIA_NOT_PRESENT; */
106 else
107 {
108 rc = enmTxDir == PDMMEDIATXDIR_NONE
109 ? VERR_DEV_IO_ERROR
110 : enmTxDir == PDMMEDIATXDIR_FROM_DEVICE
111 ? VERR_READ_ERROR
112 : VERR_WRITE_ERROR;
113 if (pThis->cLogRelErrors++ < 10)
114 LogRel(("DVD scsi error: cmd={%.*Rhxs} TaskStatus=%#x key=%#x ASC=%#x ASCQ=%#x (%Rrc)\n",
115 cbCmd, pbCmd, TaskStatus, SenseData.SENSE_KEY, SenseData.ADDITIONAL_SENSE_CODE,
116 SenseData.ADDITIONAL_SENSE_CODE_QUALIFIER, rc));
117 }
118 } while (0);
119
120 (*ppScsiTaskI)->Release(ppScsiTaskI);
121
122 return rc;
123}
124
125
126DECLHIDDEN(int) drvHostBaseGetMediaSizeOs(PDRVHOSTBASE pThis, uint64_t *pcb)
127{
128 /*
129 * Try a READ_CAPACITY command...
130 */
131 struct
132 {
133 uint32_t cBlocks;
134 uint32_t cbBlock;
135 } Buf = {0, 0};
136 uint32_t cbBuf = sizeof(Buf);
137 uint8_t abCmd[16] =
138 {
139 SCSI_READ_CAPACITY, 0, 0, 0, 0, 0, 0,
140 0,0,0,0,0,0,0,0,0
141 };
142 int rc = drvHostBaseScsiCmdOs(pThis, abCmd, 6, PDMMEDIATXDIR_FROM_DEVICE, &Buf, &cbBuf, NULL, 0, 0);
143 if (RT_SUCCESS(rc))
144 {
145 Assert(cbBuf == sizeof(Buf));
146 Buf.cBlocks = RT_BE2H_U32(Buf.cBlocks);
147 Buf.cbBlock = RT_BE2H_U32(Buf.cbBlock);
148 //if (Buf.cbBlock > 2048) /* everyone else is doing this... check if it needed/right.*/
149 // Buf.cbBlock = 2048;
150 pThis->cbBlock = Buf.cbBlock;
151
152 *pcb = (uint64_t)Buf.cBlocks * Buf.cbBlock;
153 }
154 return rc;
155}
156
157
158DECLHIDDEN(int) drvHostBaseReadOs(PDRVHOSTBASE pThis, uint64_t off, void *pvBuf, size_t cbRead)
159{
160 int rc = VINF_SUCCESS;
161
162 if (pThis->cbBlock)
163 {
164 /*
165 * Issue a READ(12) request.
166 */
167 do
168 {
169 const uint32_t LBA = off / pThis->cbBlock;
170 AssertReturn(!(off % pThis->cbBlock), VERR_INVALID_PARAMETER);
171 uint32_t cbRead32 = cbRead > SCSI_MAX_BUFFER_SIZE
172 ? SCSI_MAX_BUFFER_SIZE
173 : (uint32_t)cbRead;
174 const uint32_t cBlocks = cbRead32 / pThis->cbBlock;
175 AssertReturn(!(cbRead % pThis->cbBlock), VERR_INVALID_PARAMETER);
176 uint8_t abCmd[16] =
177 {
178 SCSI_READ_12, 0,
179 RT_BYTE4(LBA), RT_BYTE3(LBA), RT_BYTE2(LBA), RT_BYTE1(LBA),
180 RT_BYTE4(cBlocks), RT_BYTE3(cBlocks), RT_BYTE2(cBlocks), RT_BYTE1(cBlocks),
181 0, 0, 0, 0, 0
182 };
183 rc = drvHostBaseScsiCmdOs(pThis, abCmd, 12, PDMMEDIATXDIR_FROM_DEVICE, pvBuf, &cbRead32, NULL, 0, 0);
184
185 off += cbRead32;
186 cbRead -= cbRead32;
187 pvBuf = (uint8_t *)pvBuf + cbRead32;
188 } while ((cbRead > 0) && RT_SUCCESS(rc));
189 }
190 else
191 rc = VERR_MEDIA_NOT_PRESENT;
192
193 return rc;
194}
195
196
197DECLHIDDEN(int) drvHostBaseWriteOs(PDRVHOSTBASE pThis, uint64_t off, const void *pvBuf, size_t cbWrite)
198{
199 RT_NOREF4(pThis, off, pvBuf, cbWrite);
200 return VERR_WRITE_PROTECT;
201}
202
203
204DECLHIDDEN(int) drvHostBaseFlushOs(PDRVHOSTBASE pThis)
205{
206 RT_NOREF1(pThis);
207 return VINF_SUCCESS;
208}
209
210
211DECLHIDDEN(int) drvHostBaseDoLockOs(PDRVHOSTBASE pThis, bool fLock)
212{
213 uint8_t abCmd[16] =
214 {
215 SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL, 0, 0, 0, fLock, 0,
216 0,0,0,0,0,0,0,0,0,0
217 };
218 return drvHostBaseScsiCmdOs(pThis, abCmd, 6, PDMMEDIATXDIR_NONE, NULL, NULL, NULL, 0, 0);
219}
220
221
222DECLHIDDEN(int) drvHostBaseEjectOs(PDRVHOSTBASE pThis)
223{
224 uint8_t abCmd[16] =
225 {
226 SCSI_START_STOP_UNIT, 0, 0, 0, 2 /*eject+stop*/, 0,
227 0,0,0,0,0,0,0,0,0,0
228 };
229 return drvHostBaseScsiCmdOs(pThis, abCmd, 6, PDMMEDIATXDIR_NONE, NULL, NULL, NULL, 0, 0);
230}
231
232
233DECLHIDDEN(int) drvHostBaseQueryMediaStatusOs(PDRVHOSTBASE pThis, bool *pfMediaChanged, bool *pfMediaPresent)
234{
235 /*
236 * Issue a TEST UNIT READY request.
237 */
238 *pfMediaChanged = false;
239 *pfMediaPresent = false;
240 uint8_t abCmd[16] = { SCSI_TEST_UNIT_READY, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
241 uint8_t abSense[32];
242 int rc = drvHostBaseScsiCmdOs(pThis, abCmd, 6, PDMMEDIATXDIR_NONE, NULL, NULL, abSense, sizeof(abSense), 0);
243 if (RT_SUCCESS(rc))
244 *pfMediaPresent = true;
245 else if ( rc == VERR_UNRESOLVED_ERROR
246 && abSense[2] == 6 /* unit attention */
247 && ( (abSense[12] == 0x29 && abSense[13] < 5 /* reset */)
248 || (abSense[12] == 0x2a && abSense[13] == 0 /* parameters changed */) //???
249 || (abSense[12] == 0x3f && abSense[13] == 0 /* target operating conditions have changed */) //???
250 || (abSense[12] == 0x3f && abSense[13] == 2 /* changed operating definition */) //???
251 || (abSense[12] == 0x3f && abSense[13] == 3 /* inquiry parameters changed */)
252 || (abSense[12] == 0x3f && abSense[13] == 5 /* device identifier changed */)
253 )
254 )
255 {
256 *pfMediaPresent = false;
257 *pfMediaChanged = true;
258 rc = VINF_SUCCESS;
259 /** @todo check this media change stuff on Darwin. */
260 }
261
262 return rc;
263}
264
265
266DECLHIDDEN(int) drvHostBasePollerWakeupOs(PDRVHOSTBASE pThis)
267{
268 return RTSemEventSignal(pThis->EventPoller);
269}
270
271
272DECLHIDDEN(void) drvHostBaseDestructOs(PDRVHOSTBASE pThis)
273{
274 if (pThis->EventPoller != NULL)
275 {
276 RTSemEventDestroy(pThis->EventPoller);
277 pThis->EventPoller = NULL;
278 }
279
280 if (pThis->hFileDevice != NIL_RTFILE)
281 {
282 int rc = RTFileClose(pThis->hFileDevice);
283 AssertRC(rc);
284 pThis->hFileDevice = NIL_RTFILE;
285 }
286}
287
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