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 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* 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 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 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 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 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 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 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 330 init_hardware(void) 331 { 332 TRACE(("remote_disk: init_hardware()\n")); 333 334 return B_OK; 335 } 336 337 338 status_t 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 362 uninit_driver(void) 363 { 364 TRACE(("remote_disk: uninit_driver()\n")); 365 366 delete[] sDevices; 367 } 368 369 370 const char** 371 publish_devices(void) 372 { 373 TRACE(("remote_disk: publish_devices()\n")); 374 return kPublishedNames; 375 } 376 377 378 device_hooks* 379 find_device(const char* name) 380 { 381 TRACE(("remote_disk: find_device(%s)\n", name)); 382 return &sDataDeviceHooks; 383 } 384 385