VirtualBox

source: vbox/trunk/src/VBox/Devices/Storage/DrvHostBase-darwin.cpp@ 64252

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

Devices/Storage/DrvHost*: Move destroying the host specific resources to the host specific code

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.5 KB
Line 
1/* $Id: DrvHostBase-darwin.cpp 64252 2016-10-13 14:20:01Z vboxsync $ */
2/** @file
3 * DrvHostBase - Host base drive access driver, OS X 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 <mach/mach.h>
19#include <Carbon/Carbon.h>
20#include <IOKit/IOKitLib.h>
21#include <IOKit/storage/IOStorageDeviceCharacteristics.h>
22#include <IOKit/scsi/SCSITaskLib.h>
23#include <IOKit/scsi/SCSICommandOperationCodes.h>
24#include <IOKit/IOBSD.h>
25#include <DiskArbitration/DiskArbitration.h>
26#include <mach/mach_error.h>
27#include <VBox/scsi.h>
28
29#include "DrvHostBase.h"
30
31DECLHIDDEN(int) drvHostBaseScsiCmdOs(PDRVHOSTBASE pThis, const uint8_t *pbCmd, size_t cbCmd, PDMMEDIATXDIR enmTxDir,
32 void *pvBuf, uint32_t *pcbBuf, uint8_t *pbSense, size_t cbSense, uint32_t cTimeoutMillies)
33{
34 /*
35 * Minimal input validation.
36 */
37 Assert(enmTxDir == PDMMEDIATXDIR_NONE || enmTxDir == PDMMEDIATXDIR_FROM_DEVICE || enmTxDir == PDMMEDIATXDIR_TO_DEVICE);
38 Assert(!pvBuf || pcbBuf);
39 Assert(pvBuf || enmTxDir == PDMMEDIATXDIR_NONE);
40 Assert(pbSense || !cbSense);
41 AssertPtr(pbCmd);
42 Assert(cbCmd <= 16 && cbCmd >= 1);
43 const uint32_t cbBuf = pcbBuf ? *pcbBuf : 0;
44 if (pcbBuf)
45 *pcbBuf = 0;
46
47 Assert(pThis->ppScsiTaskDI);
48
49 int rc = VERR_GENERAL_FAILURE;
50 SCSITaskInterface **ppScsiTaskI = (*pThis->ppScsiTaskDI)->CreateSCSITask(pThis->ppScsiTaskDI);
51 if (!ppScsiTaskI)
52 return VERR_NO_MEMORY;
53 do
54 {
55 /* Setup the scsi command. */
56 SCSICommandDescriptorBlock cdb = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
57 memcpy(&cdb[0], pbCmd, cbCmd);
58 IOReturn irc = (*ppScsiTaskI)->SetCommandDescriptorBlock(ppScsiTaskI, cdb, cbCmd);
59 AssertBreak(irc == kIOReturnSuccess);
60
61 /* Setup the buffer. */
62 if (enmTxDir == PDMMEDIATXDIR_NONE)
63 irc = (*ppScsiTaskI)->SetScatterGatherEntries(ppScsiTaskI, NULL, 0, 0, kSCSIDataTransfer_NoDataTransfer);
64 else
65 {
66 IOVirtualRange Range = { (IOVirtualAddress)pvBuf, cbBuf };
67 irc = (*ppScsiTaskI)->SetScatterGatherEntries(ppScsiTaskI, &Range, 1, cbBuf,
68 enmTxDir == PDMMEDIATXDIR_FROM_DEVICE
69 ? kSCSIDataTransfer_FromTargetToInitiator
70 : kSCSIDataTransfer_FromInitiatorToTarget);
71 }
72 AssertBreak(irc == kIOReturnSuccess);
73
74 /* Set the timeout. */
75 irc = (*ppScsiTaskI)->SetTimeoutDuration(ppScsiTaskI, cTimeoutMillies ? cTimeoutMillies : 30000 /*ms*/);
76 AssertBreak(irc == kIOReturnSuccess);
77
78 /* Execute the command and get the response. */
79 SCSI_Sense_Data SenseData = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
80 SCSIServiceResponse ServiceResponse = kSCSIServiceResponse_Request_In_Process;
81 SCSITaskStatus TaskStatus = kSCSITaskStatus_GOOD;
82 UInt64 cbReturned = 0;
83 irc = (*ppScsiTaskI)->ExecuteTaskSync(ppScsiTaskI, &SenseData, &TaskStatus, &cbReturned);
84 AssertBreak(irc == kIOReturnSuccess);
85 if (pcbBuf)
86 *pcbBuf = (int32_t)cbReturned;
87
88 irc = (*ppScsiTaskI)->GetSCSIServiceResponse(ppScsiTaskI, &ServiceResponse);
89 AssertBreak(irc == kIOReturnSuccess);
90 AssertBreak(ServiceResponse == kSCSIServiceResponse_TASK_COMPLETE);
91
92 if (TaskStatus == kSCSITaskStatus_GOOD)
93 rc = VINF_SUCCESS;
94 else if ( TaskStatus == kSCSITaskStatus_CHECK_CONDITION
95 && pbSense)
96 {
97 memset(pbSense, 0, cbSense); /* lazy */
98 memcpy(pbSense, &SenseData, RT_MIN(sizeof(SenseData), cbSense));
99 rc = VERR_UNRESOLVED_ERROR;
100 }
101 /** @todo convert sense codes when caller doesn't wish to do this himself. */
102 /*else if ( TaskStatus == kSCSITaskStatus_CHECK_CONDITION
103 && SenseData.ADDITIONAL_SENSE_CODE == 0x3A)
104 rc = VERR_MEDIA_NOT_PRESENT; */
105 else
106 {
107 rc = enmTxDir == PDMMEDIATXDIR_NONE
108 ? VERR_DEV_IO_ERROR
109 : enmTxDir == PDMMEDIATXDIR_FROM_DEVICE
110 ? VERR_READ_ERROR
111 : VERR_WRITE_ERROR;
112 if (pThis->cLogRelErrors++ < 10)
113 LogRel(("DVD scsi error: cmd={%.*Rhxs} TaskStatus=%#x key=%#x ASC=%#x ASCQ=%#x (%Rrc)\n",
114 cbCmd, pbCmd, TaskStatus, SenseData.SENSE_KEY, SenseData.ADDITIONAL_SENSE_CODE,
115 SenseData.ADDITIONAL_SENSE_CODE_QUALIFIER, rc));
116 }
117 } while (0);
118
119 (*ppScsiTaskI)->Release(ppScsiTaskI);
120
121 return rc;
122}
123
124
125DECLHIDDEN(int) drvHostBaseGetMediaSizeOs(PDRVHOSTBASE pThis, uint64_t *pcb)
126{
127 /*
128 * Try a READ_CAPACITY command...
129 */
130 struct
131 {
132 uint32_t cBlocks;
133 uint32_t cbBlock;
134 } Buf = {0, 0};
135 uint32_t cbBuf = sizeof(Buf);
136 uint8_t abCmd[16] =
137 {
138 SCSI_READ_CAPACITY, 0, 0, 0, 0, 0, 0,
139 0,0,0,0,0,0,0,0,0
140 };
141 int rc = drvHostBaseScsiCmdOs(pThis, abCmd, 6, PDMMEDIATXDIR_FROM_DEVICE, &Buf, &cbBuf, NULL, 0, 0);
142 if (RT_SUCCESS(rc))
143 {
144 Assert(cbBuf == sizeof(Buf));
145 Buf.cBlocks = RT_BE2H_U32(Buf.cBlocks);
146 Buf.cbBlock = RT_BE2H_U32(Buf.cbBlock);
147 //if (Buf.cbBlock > 2048) /* everyone else is doing this... check if it needed/right.*/
148 // Buf.cbBlock = 2048;
149 pThis->cbBlock = Buf.cbBlock;
150
151 *pcb = (uint64_t)Buf.cBlocks * Buf.cbBlock;
152 }
153 return rc;
154}
155
156
157DECLHIDDEN(int) drvHostBaseReadOs(PDRVHOSTBASE pThis, uint64_t off, void *pvBuf, size_t cbRead)
158{
159 int rc = VINF_SUCCESS;
160
161 if ( pThis->ppScsiTaskDI
162 && 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) drvHostBasePollerWakeupOs(PDRVHOSTBASE pThis)
212{
213 return RTSemEventSignal(pThis->EventPoller);
214}
215
216
217DECLHIDDEN(void) drvHostBaseDestructOs(PDRVHOSTBASE pThis)
218{
219 if (pThis->EventPoller != NULL)
220 {
221 RTSemEventDestroy(pThis->EventPoller);
222 pThis->EventPoller = NULL;
223 }
224
225 /*
226 * The unclaiming doesn't seem to mean much, the DVD is actually
227 * remounted when we release exclusive access. I'm not quite sure
228 * if I should put the unclaim first or not...
229 *
230 * Anyway, that it's automatically remounted very good news for us,
231 * because that means we don't have to mess with that ourselves. Of
232 * course there is the unlikely scenario that we've succeeded in claiming
233 * and umount the DVD but somehow failed to gain exclusive scsi access...
234 */
235 if (pThis->ppScsiTaskDI)
236 {
237 LogFlow(("%s-%d: releasing exclusive scsi access!\n", pDrvIns->pReg->szName, pDrvIns->iInstance));
238 (*pThis->ppScsiTaskDI)->ReleaseExclusiveAccess(pThis->ppScsiTaskDI);
239 (*pThis->ppScsiTaskDI)->Release(pThis->ppScsiTaskDI);
240 pThis->ppScsiTaskDI = NULL;
241 }
242 if (pThis->pDADisk)
243 {
244 LogFlow(("%s-%d: unclaiming the disk!\n", pDrvIns->pReg->szName, pDrvIns->iInstance));
245 DADiskUnclaim(pThis->pDADisk);
246 CFRelease(pThis->pDADisk);
247 pThis->pDADisk = NULL;
248 }
249 if (pThis->ppMMCDI)
250 {
251 LogFlow(("%s-%d: releasing the MMC object!\n", pDrvIns->pReg->szName, pDrvIns->iInstance));
252 (*pThis->ppMMCDI)->Release(pThis->ppMMCDI);
253 pThis->ppMMCDI = NULL;
254 }
255 if (pThis->MasterPort != IO_OBJECT_NULL)
256 {
257 mach_port_deallocate(mach_task_self(), pThis->MasterPort);
258 pThis->MasterPort = IO_OBJECT_NULL;
259 }
260 if (pThis->pDASession)
261 {
262 LogFlow(("%s-%d: releasing the DA session!\n", pDrvIns->pReg->szName, pDrvIns->iInstance));
263 CFRelease(pThis->pDASession);
264 pThis->pDASession = NULL;
265 }
266}
267
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