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