1 /*
2 * Copyright 2007, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
5
6 #include <string.h>
7
8 #include <KernelExport.h>
9 #include <Drivers.h>
10
11 #include <lock.h>
12 #include <util/AutoLock.h>
13 #include <util/kernel_cpp.h>
14
15 #include "RemoteDisk.h"
16
17
18 //#define TRACE_REMOTE_DISK
19 #ifdef TRACE_REMOTE_DISK
20 # define TRACE(x) dprintf x
21 #else
22 # define TRACE(x) do {} while (false)
23 #endif
24
25
26 const bigtime_t kInitRetryDelay = 10 * 1000000LL; // 10 s
27
28 enum {
29 MAX_REMOTE_DISKS = 1
30 };
31
32
33 struct RemoteDiskDevice : recursive_lock {
34 RemoteDisk* remoteDisk;
35 bigtime_t lastInitRetryTime;
36
RemoteDiskDeviceRemoteDiskDevice37 RemoteDiskDevice()
38 :
39 remoteDisk(NULL),
40 lastInitRetryTime(-1)
41 {
42 }
43
~RemoteDiskDeviceRemoteDiskDevice44 ~RemoteDiskDevice()
45 {
46 delete remoteDisk;
47 Uninit();
48 }
49
InitRemoteDiskDevice50 status_t Init()
51 {
52 recursive_lock_init(this, "remote disk device");
53 return B_OK;
54 }
55
UninitRemoteDiskDevice56 void Uninit()
57 {
58 recursive_lock_destroy(this);
59 }
60
LazyInitDiskRemoteDiskDevice61 status_t LazyInitDisk()
62 {
63 if (remoteDisk)
64 return B_OK;
65
66 // don't try to init, if the last attempt wasn't long enough ago
67 if (lastInitRetryTime >= 0
68 && system_time() < lastInitRetryTime + kInitRetryDelay) {
69 return B_ERROR;
70 }
71
72 // create the object
73 remoteDisk = new(nothrow) RemoteDisk;
74 if (!remoteDisk) {
75 lastInitRetryTime = system_time();
76 return B_NO_MEMORY;
77 }
78
79 // find a server
80 TRACE(("remote_disk: FindAnyRemoteDisk()\n"));
81 status_t error = remoteDisk->FindAnyRemoteDisk();
82 if (error != B_OK) {
83 delete remoteDisk;
84 remoteDisk = NULL;
85 lastInitRetryTime = system_time();
86 return B_NO_MEMORY;
87 }
88
89 return B_OK;
90 }
91
GetGeometryRemoteDiskDevice92 void GetGeometry(device_geometry* geometry, bool bios)
93 {
94 // TODO: Respect "bios" argument!
95 geometry->bytes_per_sector = REMOTE_DISK_BLOCK_SIZE;
96 geometry->sectors_per_track = 1;
97 geometry->cylinder_count = remoteDisk->Size() / REMOTE_DISK_BLOCK_SIZE;
98 geometry->head_count = 1;
99 geometry->device_type = B_DISK;
100 geometry->removable = true;
101 geometry->read_only = remoteDisk->IsReadOnly();
102 geometry->write_once = false;
103 geometry->bytes_per_physical_sector = REMOTE_DISK_BLOCK_SIZE;
104 }
105 };
106
107 typedef RecursiveLocker DeviceLocker;
108
109
110 static const char* kPublishedNames[] = {
111 "disk/virtual/remote_disk/0/raw",
112 // "misc/remote_disk_control",
113 NULL
114 };
115
116 static RemoteDiskDevice* sDevices;
117
118
119 // #pragma mark - internal functions
120
121
122 // device_for_name
123 static RemoteDiskDevice*
device_for_name(const char * name)124 device_for_name(const char* name)
125 {
126 for (int i = 0; i < MAX_REMOTE_DISKS; i++) {
127 if (strcmp(name, kPublishedNames[i]) == 0)
128 return sDevices + i;
129 }
130 return NULL;
131 }
132
133
134 // #pragma mark - data device hooks
135
136
137 static status_t
remote_disk_open(const char * name,uint32 flags,void ** cookie)138 remote_disk_open(const char* name, uint32 flags, void** cookie)
139 {
140 RemoteDiskDevice* device = device_for_name(name);
141 TRACE(("remote_disk_open(\"%s\") -> %p\n", name, device));
142 if (!device)
143 return B_BAD_VALUE;
144
145 DeviceLocker locker(device);
146 status_t error = device->LazyInitDisk();
147 if (error != B_OK)
148 return error;
149
150 *cookie = device;
151
152 return B_OK;
153 }
154
155
156 static status_t
remote_disk_close(void * cookie)157 remote_disk_close(void* cookie)
158 {
159 TRACE(("remote_disk_close(%p)\n", cookie));
160
161 // nothing to do
162 return B_OK;
163 }
164
165
166 static status_t
remote_disk_read(void * cookie,off_t position,void * buffer,size_t * numBytes)167 remote_disk_read(void* cookie, off_t position, void* buffer, size_t* numBytes)
168 {
169 TRACE(("remote_disk_read(%p, %lld, %p, %lu)\n", cookie, position, buffer,
170 *numBytes));
171
172 RemoteDiskDevice* device = (RemoteDiskDevice*)cookie;
173 DeviceLocker locker(device);
174
175 ssize_t bytesRead = device->remoteDisk->ReadAt(position, buffer, *numBytes);
176 if (bytesRead < 0) {
177 *numBytes = 0;
178 TRACE(("remote_disk_read() failed: %s\n", strerror(bytesRead)));
179 return bytesRead;
180 }
181
182 *numBytes = bytesRead;
183 TRACE(("remote_disk_read() done: %ld\n", bytesRead));
184 return B_OK;
185 }
186
187
188 static status_t
remote_disk_write(void * cookie,off_t position,const void * buffer,size_t * numBytes)189 remote_disk_write(void* cookie, off_t position, const void* buffer,
190 size_t* numBytes)
191 {
192 TRACE(("remote_disk_write(%p, %lld, %p, %lu)\n", cookie, position, buffer,
193 *numBytes));
194
195 RemoteDiskDevice* device = (RemoteDiskDevice*)cookie;
196 DeviceLocker locker(device);
197
198 ssize_t bytesWritten = device->remoteDisk->WriteAt(position, buffer,
199 *numBytes);
200 if (bytesWritten < 0) {
201 *numBytes = 0;
202 TRACE(("remote_disk_write() failed: %s\n", strerror(bytesRead)));
203 return bytesWritten;
204 }
205
206 *numBytes = bytesWritten;
207 TRACE(("remote_disk_written() done: %ld\n", bytesWritten));
208 return B_OK;
209 }
210
211
212 static status_t
remote_disk_control(void * cookie,uint32 op,void * arg,size_t len)213 remote_disk_control(void* cookie, uint32 op, void* arg, size_t len)
214 {
215 TRACE(("remote_disk_control(%p, %lu, %p, %lu)\n", cookie, op, arg, len));
216
217 RemoteDiskDevice* device = (RemoteDiskDevice*)cookie;
218 DeviceLocker locker(device);
219
220 // used data device
221 switch (op) {
222 case B_GET_DEVICE_SIZE:
223 TRACE(("remote_disk: B_GET_DEVICE_SIZE\n"));
224 *(size_t*)arg = device->remoteDisk->Size();
225 return B_OK;
226
227 case B_SET_NONBLOCKING_IO:
228 TRACE(("remote_disk: B_SET_NONBLOCKING_IO\n"));
229 return B_OK;
230
231 case B_SET_BLOCKING_IO:
232 TRACE(("remote_disk: B_SET_BLOCKING_IO\n"));
233 return B_OK;
234
235 case B_GET_READ_STATUS:
236 TRACE(("remote_disk: B_GET_READ_STATUS\n"));
237 *(bool*)arg = true;
238 return B_OK;
239
240 case B_GET_WRITE_STATUS:
241 TRACE(("remote_disk: B_GET_WRITE_STATUS\n"));
242 *(bool*)arg = true;
243 return B_OK;
244
245 case B_GET_ICON:
246 {
247 TRACE(("remote_disk: B_GET_ICON\n"));
248 return B_BAD_VALUE;
249 }
250
251 case B_GET_BIOS_GEOMETRY:
252 case B_GET_GEOMETRY:
253 {
254 TRACE(("remote_disk: %s\n",
255 op == B_GET_BIOS_GEOMETRY ? "B_GET_BIOS_GEOMETRY" : "B_GET_GEOMETRY"));
256 if (arg == NULL || len > sizeof(device_geometry))
257 return B_BAD_VALUE;
258
259 device_geometry geometry;
260 device->GetGeometry(&geometry, op == B_GET_BIOS_GEOMETRY);
261 return user_memcpy(arg, &geometry, len);
262 }
263
264 case B_GET_MEDIA_STATUS:
265 TRACE(("remote_disk: B_GET_MEDIA_STATUS\n"));
266 *(status_t*)arg = B_NO_ERROR;
267 return B_OK;
268
269 case B_SET_UNINTERRUPTABLE_IO:
270 TRACE(("remote_disk: B_SET_UNINTERRUPTABLE_IO\n"));
271 return B_OK;
272
273 case B_SET_INTERRUPTABLE_IO:
274 TRACE(("remote_disk: B_SET_INTERRUPTABLE_IO\n"));
275 return B_OK;
276
277 case B_FLUSH_DRIVE_CACHE:
278 TRACE(("remote_disk: B_FLUSH_DRIVE_CACHE\n"));
279 return B_OK;
280
281 case B_GET_BIOS_DRIVE_ID:
282 TRACE(("remote_disk: B_GET_BIOS_DRIVE_ID\n"));
283 *(uint8*)arg = 0xF8;
284 return B_OK;
285
286 case B_GET_DRIVER_FOR_DEVICE:
287 case B_SET_DEVICE_SIZE:
288 case B_SET_PARTITION:
289 case B_FORMAT_DEVICE:
290 case B_EJECT_DEVICE:
291 case B_LOAD_MEDIA:
292 case B_GET_NEXT_OPEN_DEVICE:
293 TRACE(("remote_disk: another ioctl: %lx (%lu)\n", op, op));
294 return B_BAD_VALUE;
295
296 default:
297 TRACE(("remote_disk: unknown ioctl: %lx (%lu)\n", op, op));
298 return B_BAD_VALUE;
299 }
300 }
301
302
303 static status_t
remote_disk_free(void * cookie)304 remote_disk_free(void* cookie)
305 {
306 TRACE(("remote_disk_free(%p)\n", cookie));
307
308 // nothing to do
309 return B_OK;
310 }
311
312
313 static device_hooks sDataDeviceHooks = {
314 remote_disk_open,
315 remote_disk_close,
316 remote_disk_free,
317 remote_disk_control,
318 remote_disk_read,
319 remote_disk_write
320 };
321
322
323 // #pragma mark - public API
324
325
326 int32 api_version = B_CUR_DRIVER_API_VERSION;
327
328
329 status_t
init_hardware(void)330 init_hardware(void)
331 {
332 TRACE(("remote_disk: init_hardware()\n"));
333
334 return B_OK;
335 }
336
337
338 status_t
init_driver(void)339 init_driver(void)
340 {
341 TRACE(("remote_disk: init_driver()\n"));
342
343 sDevices = new(nothrow) RemoteDiskDevice[MAX_REMOTE_DISKS];
344 if (!sDevices)
345 return B_NO_MEMORY;
346
347 status_t error = B_OK;
348 for (int i = 0; error == B_OK && i < MAX_REMOTE_DISKS; i++)
349 error = sDevices[i].Init();
350
351 if (error != B_OK) {
352 delete[] sDevices;
353 sDevices = NULL;
354 return error;
355 }
356
357 return B_OK;
358 }
359
360
361 void
uninit_driver(void)362 uninit_driver(void)
363 {
364 TRACE(("remote_disk: uninit_driver()\n"));
365
366 delete[] sDevices;
367 }
368
369
370 const char**
publish_devices(void)371 publish_devices(void)
372 {
373 TRACE(("remote_disk: publish_devices()\n"));
374 return kPublishedNames;
375 }
376
377
378 device_hooks*
find_device(const char * name)379 find_device(const char* name)
380 {
381 TRACE(("remote_disk: find_device(%s)\n", name));
382 return &sDataDeviceHooks;
383 }
384
385