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