1 /* 2 * Copyright 2013, Jérôme Duval, korli@users.berlios.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <virtio.h> 8 9 #include "virtio_blk.h" 10 11 12 struct DMAResource; 13 struct IOScheduler; 14 15 16 static const uint8 kDriveIcon[] = { 17 0x6e, 0x63, 0x69, 0x66, 0x08, 0x03, 0x01, 0x00, 0x00, 0x02, 0x00, 0x16, 18 0x02, 0x3c, 0xc7, 0xee, 0x38, 0x9b, 0xc0, 0xba, 0x16, 0x57, 0x3e, 0x39, 19 0xb0, 0x49, 0x77, 0xc8, 0x42, 0xad, 0xc7, 0x00, 0xff, 0xff, 0xd3, 0x02, 20 0x00, 0x06, 0x02, 0x3c, 0x96, 0x32, 0x3a, 0x4d, 0x3f, 0xba, 0xfc, 0x01, 21 0x3d, 0x5a, 0x97, 0x4b, 0x57, 0xa5, 0x49, 0x84, 0x4d, 0x00, 0x47, 0x47, 22 0x47, 0xff, 0xa5, 0xa0, 0xa0, 0x02, 0x00, 0x16, 0x02, 0xbc, 0x59, 0x2f, 23 0xbb, 0x29, 0xa7, 0x3c, 0x0c, 0xe4, 0xbd, 0x0b, 0x7c, 0x48, 0x92, 0xc0, 24 0x4b, 0x79, 0x66, 0x00, 0x7d, 0xff, 0xd4, 0x02, 0x00, 0x06, 0x02, 0x38, 25 0xdb, 0xb4, 0x39, 0x97, 0x33, 0xbc, 0x4a, 0x33, 0x3b, 0xa5, 0x42, 0x48, 26 0x6e, 0x66, 0x49, 0xee, 0x7b, 0x00, 0x59, 0x67, 0x56, 0xff, 0xeb, 0xb2, 27 0xb2, 0x03, 0xa7, 0xff, 0x00, 0x03, 0xff, 0x00, 0x00, 0x04, 0x01, 0x80, 28 0x07, 0x0a, 0x06, 0x22, 0x3c, 0x22, 0x49, 0x44, 0x5b, 0x5a, 0x3e, 0x5a, 29 0x31, 0x39, 0x25, 0x0a, 0x04, 0x22, 0x3c, 0x44, 0x4b, 0x5a, 0x31, 0x39, 30 0x25, 0x0a, 0x04, 0x44, 0x4b, 0x44, 0x5b, 0x5a, 0x3e, 0x5a, 0x31, 0x0a, 31 0x04, 0x22, 0x3c, 0x22, 0x49, 0x44, 0x5b, 0x44, 0x4b, 0x08, 0x02, 0x27, 32 0x43, 0xb8, 0x14, 0xc1, 0xf1, 0x08, 0x02, 0x26, 0x43, 0x29, 0x44, 0x0a, 33 0x05, 0x44, 0x5d, 0x49, 0x5d, 0x60, 0x3e, 0x5a, 0x3b, 0x5b, 0x3f, 0x08, 34 0x0a, 0x07, 0x01, 0x06, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x10, 0x01, 0x17, 35 0x84, 0x00, 0x04, 0x0a, 0x01, 0x01, 0x01, 0x00, 0x0a, 0x02, 0x01, 0x02, 36 0x00, 0x0a, 0x03, 0x01, 0x03, 0x00, 0x0a, 0x04, 0x01, 0x04, 0x10, 0x01, 37 0x17, 0x85, 0x20, 0x04, 0x0a, 0x06, 0x01, 0x05, 0x30, 0x24, 0xb3, 0x99, 38 0x01, 0x17, 0x82, 0x00, 0x04, 0x0a, 0x05, 0x01, 0x05, 0x30, 0x20, 0xb2, 39 0xe6, 0x01, 0x17, 0x82, 0x00, 0x04 40 }; 41 42 43 #define VIRTIO_BLOCK_DRIVER_MODULE_NAME "drivers/disk/virtual/virtio_block/driver_v1" 44 #define VIRTIO_BLOCK_DEVICE_MODULE_NAME "drivers/disk/virtual/virtio_block/device_v1" 45 #define VIRTIO_BLOCK_DEVICE_ID_GENERATOR "virtio_block/device_id" 46 47 48 typedef struct { 49 device_node* node; 50 ::virtio_device virtio_device; 51 virtio_device_interface* virtio; 52 ::virtio_queue virtio_queue; 53 IOScheduler* io_scheduler; 54 DMAResource* dma_resource; 55 56 struct virtio_blk_config config; 57 58 uint32 features; 59 uint64 capacity; 60 uint32 block_size; 61 status_t media_status; 62 63 sem_id sem_cb; 64 } virtio_block_driver_info; 65 66 67 typedef struct { 68 virtio_block_driver_info* info; 69 } virtio_block_handle; 70 71 72 #include <stdio.h> 73 #include <string.h> 74 #include <stdlib.h> 75 76 #include <fs/devfs.h> 77 78 #include "dma_resources.h" 79 #include "IORequest.h" 80 #include "IOSchedulerSimple.h" 81 82 83 //#define TRACE_VIRTIO_BLOCK 84 #ifdef TRACE_VIRTIO_BLOCK 85 # define TRACE(x...) dprintf("virtio_block: " x) 86 #else 87 # define TRACE(x...) ; 88 #endif 89 #define ERROR(x...) dprintf("\33[33mvirtio_block:\33[0m " x) 90 #define CALLED() TRACE("CALLED %s\n", __PRETTY_FUNCTION__) 91 92 93 static device_manager_info* sDeviceManager; 94 95 96 void virtio_block_set_capacity(virtio_block_driver_info* info, uint64 capacity, 97 uint32 blockSize); 98 99 100 const char * 101 get_feature_name(uint32 feature) 102 { 103 switch (feature) { 104 case VIRTIO_BLK_F_BARRIER: 105 return "host barrier"; 106 case VIRTIO_BLK_F_SIZE_MAX: 107 return "maximum segment size"; 108 case VIRTIO_BLK_F_SEG_MAX: 109 return "maximum segment count"; 110 case VIRTIO_BLK_F_GEOMETRY: 111 return "disk geometry"; 112 case VIRTIO_BLK_F_RO: 113 return "read only"; 114 case VIRTIO_BLK_F_BLK_SIZE: 115 return "block size"; 116 case VIRTIO_BLK_F_SCSI: 117 return "scsi commands"; 118 case VIRTIO_BLK_F_FLUSH: 119 return "flush command"; 120 case VIRTIO_BLK_F_TOPOLOGY: 121 return "topology"; 122 } 123 return NULL; 124 } 125 126 127 static status_t 128 get_geometry(virtio_block_handle* handle, device_geometry* geometry) 129 { 130 virtio_block_driver_info* info = handle->info; 131 132 devfs_compute_geometry_size(geometry, info->capacity, info->block_size); 133 134 geometry->device_type = B_DISK; 135 geometry->removable = false; 136 137 geometry->read_only = ((info->features & VIRTIO_BLK_F_RO) != 0); 138 geometry->write_once = false; 139 140 TRACE("virtio_block: get_geometry(): %ld, %ld, %ld, %ld, %d, %d, %d, %d\n", 141 geometry->bytes_per_sector, geometry->sectors_per_track, 142 geometry->cylinder_count, geometry->head_count, geometry->device_type, 143 geometry->removable, geometry->read_only, geometry->write_once); 144 145 return B_OK; 146 } 147 148 149 static int 150 log2(uint32 x) 151 { 152 int y; 153 154 for (y = 31; y >= 0; --y) { 155 if (x == ((uint32)1 << y)) 156 break; 157 } 158 159 return y; 160 } 161 162 163 static void 164 virtio_block_config_callback(void* driverCookie) 165 { 166 virtio_block_driver_info* info = (virtio_block_driver_info*)driverCookie; 167 168 status_t status = info->virtio->read_device_config(info->virtio_device, 0, 169 &info->config, sizeof(struct virtio_blk_config)); 170 if (status != B_OK) 171 return; 172 173 uint32 block_size = 512; 174 if ((info->features & VIRTIO_BLK_F_BLK_SIZE) != 0) 175 block_size = info->config.blk_size; 176 uint64 capacity = info->config.capacity * 512 / block_size; 177 178 if (block_size != info->block_size || capacity != info->capacity) { 179 virtio_block_set_capacity(info, capacity, block_size); 180 info->media_status = B_DEV_MEDIA_CHANGED; 181 } 182 183 } 184 185 186 static void 187 virtio_block_callback(void* driverCookie, void* cookie) 188 { 189 virtio_block_driver_info* info = (virtio_block_driver_info*)cookie; 190 191 release_sem_etc(info->sem_cb, 1, B_DO_NOT_RESCHEDULE); 192 } 193 194 195 static status_t 196 do_io(void* cookie, IOOperation* operation) 197 { 198 virtio_block_driver_info* info = (virtio_block_driver_info*)cookie; 199 200 size_t bytesTransferred = 0; 201 status_t status = B_OK; 202 203 physical_entry entries[operation->VecCount() + 2]; 204 205 void *buffer = malloc(sizeof(struct virtio_blk_outhdr) + sizeof(uint8)); 206 struct virtio_blk_outhdr *header = (struct virtio_blk_outhdr*)buffer; 207 header->type = operation->IsWrite() ? VIRTIO_BLK_T_OUT : VIRTIO_BLK_T_IN; 208 header->sector = operation->Offset() / 512; 209 header->ioprio = 1; 210 211 uint8* ack = (uint8*)buffer + sizeof(struct virtio_blk_outhdr); 212 *ack = 0xff; 213 214 get_memory_map(buffer, sizeof(struct virtio_blk_outhdr) + sizeof(uint8), 215 &entries[0], 1); 216 entries[operation->VecCount() + 1].address = entries[0].address 217 + sizeof(struct virtio_blk_outhdr); 218 entries[operation->VecCount() + 1].size = sizeof(uint8); 219 entries[0].size = sizeof(struct virtio_blk_outhdr); 220 221 memcpy(entries + 1, operation->Vecs(), operation->VecCount() 222 * sizeof(physical_entry)); 223 224 info->virtio->queue_request_v(info->virtio_queue, entries, 225 1 + (operation->IsWrite() ? operation->VecCount() : 0 ), 226 1 + (operation->IsWrite() ? 0 : operation->VecCount()), 227 virtio_block_callback, info); 228 229 acquire_sem(info->sem_cb); 230 231 switch (*ack) { 232 case VIRTIO_BLK_S_OK: 233 status = B_OK; 234 bytesTransferred = operation->Length(); 235 break; 236 case VIRTIO_BLK_S_UNSUPP: 237 status = ENOTSUP; 238 break; 239 default: 240 status = EIO; 241 break; 242 } 243 free(buffer); 244 245 info->io_scheduler->OperationCompleted(operation, status, 246 bytesTransferred); 247 return status; 248 } 249 250 251 // #pragma mark - device module API 252 253 254 static status_t 255 virtio_block_init_device(void* _info, void** _cookie) 256 { 257 CALLED(); 258 virtio_block_driver_info* info = (virtio_block_driver_info*)_info; 259 260 device_node* parent = sDeviceManager->get_parent_node(info->node); 261 sDeviceManager->get_driver(parent, (driver_module_info **)&info->virtio, 262 (void **)&info->virtio_device); 263 sDeviceManager->put_node(parent); 264 265 info->virtio->negociate_features(info->virtio_device, 266 VIRTIO_BLK_F_BARRIER | VIRTIO_BLK_F_SIZE_MAX 267 | VIRTIO_BLK_F_SEG_MAX | VIRTIO_BLK_F_GEOMETRY 268 | VIRTIO_BLK_F_RO | VIRTIO_BLK_F_BLK_SIZE 269 | VIRTIO_BLK_F_FLUSH | VIRTIO_FEATURE_RING_INDIRECT_DESC, 270 &info->features, &get_feature_name); 271 272 status_t status = info->virtio->read_device_config( 273 info->virtio_device, 0, &info->config, 274 sizeof(struct virtio_blk_config)); 275 if (status != B_OK) 276 return status; 277 278 // and get (initial) capacity 279 uint32 block_size = 512; 280 if ((info->features & VIRTIO_BLK_F_BLK_SIZE) != 0) 281 block_size = info->config.blk_size; 282 uint64 capacity = info->config.capacity * 512 / block_size; 283 284 virtio_block_set_capacity(info, capacity, block_size); 285 286 TRACE("virtio_block: capacity: %" B_PRIu64 ", block_size %" B_PRIu32 "\n", 287 info->capacity, info->block_size); 288 289 status = info->virtio->alloc_queues(info->virtio_device, 1, 290 &info->virtio_queue); 291 if (status != B_OK) { 292 ERROR("queue allocation failed (%s)\n", strerror(status)); 293 return status; 294 } 295 status = info->virtio->setup_interrupt(info->virtio_device, 296 virtio_block_config_callback, info); 297 298 *_cookie = info; 299 return status; 300 } 301 302 303 static void 304 virtio_block_uninit_device(void* _cookie) 305 { 306 CALLED(); 307 virtio_block_driver_info* info = (virtio_block_driver_info*)_cookie; 308 309 delete info->io_scheduler; 310 delete info->dma_resource; 311 } 312 313 314 static status_t 315 virtio_block_open(void* _info, const char* path, int openMode, void** _cookie) 316 { 317 CALLED(); 318 virtio_block_driver_info* info = (virtio_block_driver_info*)_info; 319 320 virtio_block_handle* handle = (virtio_block_handle*)malloc( 321 sizeof(virtio_block_handle)); 322 if (handle == NULL) 323 return B_NO_MEMORY; 324 325 handle->info = info; 326 327 *_cookie = handle; 328 return B_OK; 329 } 330 331 332 static status_t 333 virtio_block_close(void* cookie) 334 { 335 //virtio_block_handle* handle = (virtio_block_handle*)cookie; 336 CALLED(); 337 338 return B_OK; 339 } 340 341 342 static status_t 343 virtio_block_free(void* cookie) 344 { 345 CALLED(); 346 virtio_block_handle* handle = (virtio_block_handle*)cookie; 347 348 free(handle); 349 return B_OK; 350 } 351 352 353 static status_t 354 virtio_block_read(void* cookie, off_t pos, void* buffer, size_t* _length) 355 { 356 CALLED(); 357 virtio_block_handle* handle = (virtio_block_handle*)cookie; 358 size_t length = *_length; 359 360 IORequest request; 361 status_t status = request.Init(pos, (addr_t)buffer, length, false, 0); 362 if (status != B_OK) 363 return status; 364 365 status = handle->info->io_scheduler->ScheduleRequest(&request); 366 if (status != B_OK) 367 return status; 368 369 status = request.Wait(0, 0); 370 if (status == B_OK) 371 *_length = length; 372 else 373 dprintf("read(): request.Wait() returned: %s\n", strerror(status)); 374 375 return status; 376 } 377 378 379 static status_t 380 virtio_block_write(void* cookie, off_t pos, const void* buffer, 381 size_t* _length) 382 { 383 CALLED(); 384 virtio_block_handle* handle = (virtio_block_handle*)cookie; 385 size_t length = *_length; 386 387 IORequest request; 388 status_t status = request.Init(pos, (addr_t)buffer, length, true, 0); 389 if (status != B_OK) 390 return status; 391 392 status = handle->info->io_scheduler->ScheduleRequest(&request); 393 if (status != B_OK) 394 return status; 395 396 status = request.Wait(0, 0); 397 if (status == B_OK) 398 *_length = length; 399 else 400 dprintf("write(): request.Wait() returned: %s\n", strerror(status)); 401 402 return status; 403 } 404 405 406 static status_t 407 virtio_block_io(void *cookie, io_request *request) 408 { 409 CALLED(); 410 virtio_block_handle* handle = (virtio_block_handle*)cookie; 411 412 return handle->info->io_scheduler->ScheduleRequest(request); 413 } 414 415 416 static status_t 417 virtio_block_ioctl(void* cookie, uint32 op, void* buffer, size_t length) 418 { 419 CALLED(); 420 virtio_block_handle* handle = (virtio_block_handle*)cookie; 421 virtio_block_driver_info* info = handle->info; 422 423 TRACE("ioctl(op = %ld)\n", op); 424 425 switch (op) { 426 case B_GET_MEDIA_STATUS: 427 { 428 *(status_t *)buffer = info->media_status; 429 info->media_status = B_OK; 430 TRACE("B_GET_MEDIA_STATUS: 0x%08lx\n", *(status_t *)buffer); 431 return B_OK; 432 break; 433 } 434 435 case B_GET_DEVICE_SIZE: 436 { 437 size_t size = info->capacity * info->block_size; 438 return user_memcpy(buffer, &size, sizeof(size_t)); 439 } 440 441 case B_GET_GEOMETRY: 442 { 443 if (buffer == NULL /*|| length != sizeof(device_geometry)*/) 444 return B_BAD_VALUE; 445 446 device_geometry geometry; 447 status_t status = get_geometry(handle, &geometry); 448 if (status != B_OK) 449 return status; 450 451 return user_memcpy(buffer, &geometry, sizeof(device_geometry)); 452 } 453 454 case B_GET_ICON_NAME: 455 return user_strlcpy((char*)buffer, "devices/drive-harddisk", 456 B_FILE_NAME_LENGTH); 457 458 case B_GET_VECTOR_ICON: 459 { 460 // TODO: take device type into account! 461 device_icon iconData; 462 if (length != sizeof(device_icon)) 463 return B_BAD_VALUE; 464 if (user_memcpy(&iconData, buffer, sizeof(device_icon)) != B_OK) 465 return B_BAD_ADDRESS; 466 467 if (iconData.icon_size >= (int32)sizeof(kDriveIcon)) { 468 if (user_memcpy(iconData.icon_data, kDriveIcon, 469 sizeof(kDriveIcon)) != B_OK) 470 return B_BAD_ADDRESS; 471 } 472 473 iconData.icon_size = sizeof(kDriveIcon); 474 return user_memcpy(buffer, &iconData, sizeof(device_icon)); 475 } 476 477 /*case B_FLUSH_DRIVE_CACHE: 478 return synchronize_cache(info);*/ 479 } 480 481 return B_DEV_INVALID_IOCTL; 482 } 483 484 485 void 486 virtio_block_set_capacity(virtio_block_driver_info* info, uint64 capacity, 487 uint32 blockSize) 488 { 489 TRACE("set_capacity(device = %p, capacity = %Ld, blockSize = %ld)\n", 490 info, capacity, blockSize); 491 492 // get log2, if possible 493 uint32 blockShift = log2(blockSize); 494 495 if ((1UL << blockShift) != blockSize) 496 blockShift = 0; 497 498 info->capacity = capacity; 499 500 if (info->block_size != blockSize) { 501 if (info->block_size != 0) { 502 ERROR("old %" B_PRId32 ", new %" B_PRId32 "\n", info->block_size, 503 blockSize); 504 panic("updating DMAResource not yet implemented..."); 505 } 506 507 dma_restrictions restrictions; 508 memset(&restrictions, 0, sizeof(restrictions)); 509 if ((info->features & VIRTIO_BLK_F_SIZE_MAX) != 0) 510 restrictions.max_segment_size = info->config.size_max; 511 if ((info->features & VIRTIO_BLK_F_SEG_MAX) != 0) 512 restrictions.max_segment_count = info->config.seg_max; 513 514 // TODO: we need to replace the DMAResource in our IOScheduler 515 status_t status = info->dma_resource->Init(restrictions, blockSize, 516 1024, 32); 517 if (status != B_OK) 518 panic("initializing DMAResource failed: %s", strerror(status)); 519 520 info->io_scheduler = new(std::nothrow) IOSchedulerSimple( 521 info->dma_resource); 522 if (info->io_scheduler == NULL) 523 panic("allocating IOScheduler failed."); 524 525 // TODO: use whole device name here 526 status = info->io_scheduler->Init("virtio"); 527 if (status != B_OK) 528 panic("initializing IOScheduler failed: %s", strerror(status)); 529 530 info->io_scheduler->SetCallback(do_io, info); 531 } 532 533 info->block_size = blockSize; 534 } 535 536 537 // #pragma mark - driver module API 538 539 540 static float 541 virtio_block_supports_device(device_node *parent) 542 { 543 CALLED(); 544 const char *bus; 545 uint16 deviceType; 546 547 // make sure parent is really the Virtio bus manager 548 if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false)) 549 return -1; 550 551 if (strcmp(bus, "virtio")) 552 return 0.0; 553 554 // check whether it's really a Direct Access Device 555 if (sDeviceManager->get_attr_uint16(parent, VIRTIO_DEVICE_TYPE_ITEM, 556 &deviceType, true) != B_OK || deviceType != VIRTIO_DEVICE_ID_BLOCK) 557 return 0.0; 558 559 TRACE("Virtio block device found!\n"); 560 561 return 0.6; 562 } 563 564 565 static status_t 566 virtio_block_register_device(device_node *node) 567 { 568 CALLED(); 569 570 // ready to register 571 device_attr attrs[] = { 572 { NULL } 573 }; 574 575 return sDeviceManager->register_node(node, VIRTIO_BLOCK_DRIVER_MODULE_NAME, 576 attrs, NULL, NULL); 577 } 578 579 580 static status_t 581 virtio_block_init_driver(device_node *node, void **cookie) 582 { 583 CALLED(); 584 585 virtio_block_driver_info* info = (virtio_block_driver_info*)malloc( 586 sizeof(virtio_block_driver_info)); 587 if (info == NULL) 588 return B_NO_MEMORY; 589 590 memset(info, 0, sizeof(*info)); 591 592 info->media_status = B_OK; 593 info->dma_resource = new(std::nothrow) DMAResource; 594 if (info->dma_resource == NULL) { 595 free(info); 596 return B_NO_MEMORY; 597 } 598 599 info->sem_cb = create_sem(0, "virtio_block_cb"); 600 if (info->sem_cb < 0) { 601 delete info->dma_resource; 602 status_t status = info->sem_cb; 603 free(info); 604 return status; 605 } 606 info->node = node; 607 608 *cookie = info; 609 return B_OK; 610 } 611 612 613 static void 614 virtio_block_uninit_driver(void *_cookie) 615 { 616 CALLED(); 617 virtio_block_driver_info* info = (virtio_block_driver_info*)_cookie; 618 delete_sem(info->sem_cb); 619 free(info); 620 } 621 622 623 static status_t 624 virtio_block_register_child_devices(void* _cookie) 625 { 626 CALLED(); 627 virtio_block_driver_info* info = (virtio_block_driver_info*)_cookie; 628 status_t status; 629 630 int32 id = sDeviceManager->create_id(VIRTIO_BLOCK_DEVICE_ID_GENERATOR); 631 if (id < 0) 632 return id; 633 634 char name[64]; 635 snprintf(name, sizeof(name), "disk/virtual/virtio_block/%" B_PRId32 "/raw", 636 id); 637 638 status = sDeviceManager->publish_device(info->node, name, 639 VIRTIO_BLOCK_DEVICE_MODULE_NAME); 640 641 return status; 642 } 643 644 645 // #pragma mark - 646 647 648 module_dependency module_dependencies[] = { 649 {B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&sDeviceManager}, 650 {} 651 }; 652 653 struct device_module_info sVirtioBlockDevice = { 654 { 655 VIRTIO_BLOCK_DEVICE_MODULE_NAME, 656 0, 657 NULL 658 }, 659 660 virtio_block_init_device, 661 virtio_block_uninit_device, 662 NULL, // remove, 663 664 virtio_block_open, 665 virtio_block_close, 666 virtio_block_free, 667 virtio_block_read, 668 virtio_block_write, 669 virtio_block_io, 670 virtio_block_ioctl, 671 672 NULL, // select 673 NULL, // deselect 674 }; 675 676 struct driver_module_info sVirtioBlockDriver = { 677 { 678 VIRTIO_BLOCK_DRIVER_MODULE_NAME, 679 0, 680 NULL 681 }, 682 683 virtio_block_supports_device, 684 virtio_block_register_device, 685 virtio_block_init_driver, 686 virtio_block_uninit_driver, 687 virtio_block_register_child_devices, 688 NULL, // rescan 689 NULL, // removed 690 }; 691 692 module_info* modules[] = { 693 (module_info*)&sVirtioBlockDriver, 694 (module_info*)&sVirtioBlockDevice, 695 NULL 696 }; 697