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