1 /* 2 * Copyright 2019, Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Augustin Cavalier <waddlesplash> 7 */ 8 9 10 #include <stdio.h> 11 #include <stdlib.h> 12 13 #include <algorithm> 14 #include <AutoDeleter.h> 15 #include <kernel.h> 16 #include <util/AutoLock.h> 17 18 #include <fs/devfs.h> 19 #include <bus/PCI.h> 20 21 extern "C" { 22 #include <libnvme/nvme.h> 23 } 24 25 26 //#define TRACE_NVME_DISK 27 #ifdef TRACE_NVME_DISK 28 # define TRACE(x...) dprintf("nvme_disk: " x) 29 #else 30 # define TRACE(x...) ; 31 #endif 32 #define TRACE_ALWAYS(x...) dprintf("nvme_disk: " x) 33 #define TRACE_ERROR(x...) dprintf("\33[33mnvme_disk:\33[0m " x) 34 #define CALLED() TRACE("CALLED %s\n", __PRETTY_FUNCTION__) 35 36 37 static const uint8 kDriveIcon[] = { 38 0x6e, 0x63, 0x69, 0x66, 0x08, 0x03, 0x01, 0x00, 0x00, 0x02, 0x00, 0x16, 39 0x02, 0x3c, 0xc7, 0xee, 0x38, 0x9b, 0xc0, 0xba, 0x16, 0x57, 0x3e, 0x39, 40 0xb0, 0x49, 0x77, 0xc8, 0x42, 0xad, 0xc7, 0x00, 0xff, 0xff, 0xd3, 0x02, 41 0x00, 0x06, 0x02, 0x3c, 0x96, 0x32, 0x3a, 0x4d, 0x3f, 0xba, 0xfc, 0x01, 42 0x3d, 0x5a, 0x97, 0x4b, 0x57, 0xa5, 0x49, 0x84, 0x4d, 0x00, 0x47, 0x47, 43 0x47, 0xff, 0xa5, 0xa0, 0xa0, 0x02, 0x00, 0x16, 0x02, 0xbc, 0x59, 0x2f, 44 0xbb, 0x29, 0xa7, 0x3c, 0x0c, 0xe4, 0xbd, 0x0b, 0x7c, 0x48, 0x92, 0xc0, 45 0x4b, 0x79, 0x66, 0x00, 0x7d, 0xff, 0xd4, 0x02, 0x00, 0x06, 0x02, 0x38, 46 0xdb, 0xb4, 0x39, 0x97, 0x33, 0xbc, 0x4a, 0x33, 0x3b, 0xa5, 0x42, 0x48, 47 0x6e, 0x66, 0x49, 0xee, 0x7b, 0x00, 0x59, 0x67, 0x56, 0xff, 0xeb, 0xb2, 48 0xb2, 0x03, 0xa7, 0xff, 0x00, 0x03, 0xff, 0x00, 0x00, 0x04, 0x01, 0x80, 49 0x07, 0x0a, 0x06, 0x22, 0x3c, 0x22, 0x49, 0x44, 0x5b, 0x5a, 0x3e, 0x5a, 50 0x31, 0x39, 0x25, 0x0a, 0x04, 0x22, 0x3c, 0x44, 0x4b, 0x5a, 0x31, 0x39, 51 0x25, 0x0a, 0x04, 0x44, 0x4b, 0x44, 0x5b, 0x5a, 0x3e, 0x5a, 0x31, 0x0a, 52 0x04, 0x22, 0x3c, 0x22, 0x49, 0x44, 0x5b, 0x44, 0x4b, 0x08, 0x02, 0x27, 53 0x43, 0xb8, 0x14, 0xc1, 0xf1, 0x08, 0x02, 0x26, 0x43, 0x29, 0x44, 0x0a, 54 0x05, 0x44, 0x5d, 0x49, 0x5d, 0x60, 0x3e, 0x5a, 0x3b, 0x5b, 0x3f, 0x08, 55 0x0a, 0x07, 0x01, 0x06, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x10, 0x01, 0x17, 56 0x84, 0x00, 0x04, 0x0a, 0x01, 0x01, 0x01, 0x00, 0x0a, 0x02, 0x01, 0x02, 57 0x00, 0x0a, 0x03, 0x01, 0x03, 0x00, 0x0a, 0x04, 0x01, 0x04, 0x10, 0x01, 58 0x17, 0x85, 0x20, 0x04, 0x0a, 0x06, 0x01, 0x05, 0x30, 0x24, 0xb3, 0x99, 59 0x01, 0x17, 0x82, 0x00, 0x04, 0x0a, 0x05, 0x01, 0x05, 0x30, 0x20, 0xb2, 60 0xe6, 0x01, 0x17, 0x82, 0x00, 0x04 61 }; 62 63 64 #define NVME_DISK_DRIVER_MODULE_NAME "drivers/disk/nvme_disk/driver_v1" 65 #define NVME_DISK_DEVICE_MODULE_NAME "drivers/disk/nvme_disk/device_v1" 66 #define NVME_DISK_DEVICE_ID_GENERATOR "nvme_disk/device_id" 67 68 #define NVME_MAX_QPAIRS (8) 69 70 71 static device_manager_info* sDeviceManager; 72 73 typedef struct { 74 device_node* node; 75 pci_info info; 76 77 struct nvme_ctrlr* ctrlr; 78 struct nvme_ns* ns; 79 80 uint64 capacity; 81 uint32 block_size; 82 size_t max_transfer_size; 83 status_t media_status; 84 85 struct qpair_info { 86 struct nvme_qpair* qpair; 87 mutex mtx; 88 } qpairs[NVME_MAX_QPAIRS]; 89 uint32 qpair_count; 90 uint32 next_qpair; 91 } nvme_disk_driver_info; 92 typedef nvme_disk_driver_info::qpair_info qpair_info; 93 94 95 typedef struct { 96 nvme_disk_driver_info* info; 97 } nvme_disk_handle; 98 99 100 static status_t 101 get_geometry(nvme_disk_handle* handle, device_geometry* geometry) 102 { 103 nvme_disk_driver_info* info = handle->info; 104 105 devfs_compute_geometry_size(geometry, info->capacity, info->block_size); 106 107 geometry->device_type = B_DISK; 108 geometry->removable = false; 109 110 geometry->read_only = false; 111 geometry->write_once = false; 112 113 TRACE("get_geometry(): %" B_PRId32 ", %" B_PRId32 ", %" B_PRId32 ", %" B_PRId32 ", %d, %d, %d, %d\n", 114 geometry->bytes_per_sector, geometry->sectors_per_track, 115 geometry->cylinder_count, geometry->head_count, geometry->device_type, 116 geometry->removable, geometry->read_only, geometry->write_once); 117 118 return B_OK; 119 } 120 121 122 static int 123 log2(uint32 x) 124 { 125 int y; 126 127 for (y = 31; y >= 0; --y) { 128 if (x == ((uint32)1 << y)) 129 break; 130 } 131 132 return y; 133 } 134 135 136 static void 137 nvme_disk_set_capacity(nvme_disk_driver_info* info, uint64 capacity, 138 uint32 blockSize) 139 { 140 TRACE("set_capacity(device = %p, capacity = %" B_PRIu64 ", blockSize = %" B_PRIu32 ")\n", 141 info, capacity, blockSize); 142 143 // get log2, if possible 144 uint32 blockShift = log2(blockSize); 145 146 if ((1UL << blockShift) != blockSize) 147 blockShift = 0; 148 149 info->capacity = capacity; 150 info->block_size = blockSize; 151 } 152 153 154 // #pragma mark - device module API 155 156 157 static status_t 158 nvme_disk_init_device(void* _info, void** _cookie) 159 { 160 CALLED(); 161 nvme_disk_driver_info* info = (nvme_disk_driver_info*)_info; 162 163 pci_device_module_info* pci; 164 pci_device* pcidev; 165 device_node* parent = sDeviceManager->get_parent_node(info->node); 166 sDeviceManager->get_driver(parent, (driver_module_info**)&pci, 167 (void**)&pcidev); 168 pci->get_pci_info(pcidev, &info->info); 169 sDeviceManager->put_node(parent); 170 171 // construct the libnvme pci_device struct 172 pci_device* device = new pci_device; 173 device->vendor_id = info->info.vendor_id; 174 device->device_id = info->info.device_id; 175 device->subvendor_id = 0; 176 device->subdevice_id = 0; 177 178 device->domain = 0; 179 device->bus = info->info.bus; 180 device->dev = info->info.device; 181 device->func = info->info.function; 182 183 device->pci_info = &info->info; 184 185 // open the controller 186 info->ctrlr = nvme_ctrlr_open(device, NULL); 187 if (info->ctrlr == NULL) { 188 TRACE_ERROR("failed to open the controller!\n"); 189 return B_ERROR; 190 } 191 192 struct nvme_ctrlr_stat cstat; 193 int err = nvme_ctrlr_stat(info->ctrlr, &cstat); 194 if (err != 0) { 195 TRACE_ERROR("failed to get controller information!\n"); 196 return err; 197 } 198 199 TRACE_ALWAYS("attached to NVMe device \"%s (%s)\"\n", cstat.mn, cstat.sn); 200 TRACE_ALWAYS("\tmaximum transfer size: %" B_PRIuSIZE "\n", cstat.max_xfer_size); 201 TRACE_ALWAYS("\tqpair count: %d\n", cstat.io_qpairs); 202 203 // TODO: export more than just the first namespace! 204 info->ns = nvme_ns_open(info->ctrlr, cstat.ns_ids[0]); 205 if (info->ns == NULL) { 206 TRACE_ERROR("failed to open namespace!\n"); 207 return B_ERROR; 208 } 209 210 struct nvme_ns_stat nsstat; 211 err = nvme_ns_stat(info->ns, &nsstat); 212 if (err != 0) { 213 TRACE_ERROR("failed to get namespace information!\n"); 214 return err; 215 } 216 217 // store capacity information 218 nvme_disk_set_capacity(info, nsstat.sectors, nsstat.sector_size); 219 info->max_transfer_size = ROUNDDOWN(cstat.max_xfer_size, 220 nsstat.sector_size); 221 222 TRACE("capacity: %" B_PRIu64 ", block_size %" B_PRIu32 "\n", 223 info->capacity, info->block_size); 224 225 // allocate qpairs 226 info->qpair_count = info->next_qpair = 0; 227 for (uint32 i = 0; i < NVME_MAX_QPAIRS && i < cstat.io_qpairs; i++) { 228 info->qpairs[i].qpair = nvme_ioqp_get(info->ctrlr, 229 (enum nvme_qprio)0, 0); 230 if (info->qpairs[i].qpair == NULL) 231 break; 232 233 mutex_init(&info->qpairs[i].mtx, "qpair mutex"); 234 info->qpair_count++; 235 } 236 if (info->qpair_count == 0) { 237 TRACE_ERROR("failed to allocate qpairs!\n"); 238 return B_NO_MEMORY; 239 } 240 241 *_cookie = info; 242 return B_OK; 243 } 244 245 246 static void 247 nvme_disk_uninit_device(void* _cookie) 248 { 249 CALLED(); 250 nvme_disk_driver_info* info = (nvme_disk_driver_info*)_cookie; 251 } 252 253 254 static status_t 255 nvme_disk_open(void* _info, const char* path, int openMode, void** _cookie) 256 { 257 CALLED(); 258 259 nvme_disk_driver_info* info = (nvme_disk_driver_info*)_info; 260 nvme_disk_handle* handle = (nvme_disk_handle*)malloc( 261 sizeof(nvme_disk_handle)); 262 if (handle == NULL) 263 return B_NO_MEMORY; 264 265 handle->info = info; 266 267 *_cookie = handle; 268 return B_OK; 269 } 270 271 272 static status_t 273 nvme_disk_close(void* cookie) 274 { 275 CALLED(); 276 277 nvme_disk_handle* handle = (nvme_disk_handle*)cookie; 278 return B_OK; 279 } 280 281 282 static status_t 283 nvme_disk_free(void* cookie) 284 { 285 CALLED(); 286 287 nvme_disk_handle* handle = (nvme_disk_handle*)cookie; 288 free(handle); 289 return B_OK; 290 } 291 292 293 // #pragma mark - I/O functions 294 295 296 static qpair_info* 297 get_next_qpair(nvme_disk_driver_info* info) 298 { 299 return &info->qpairs[atomic_add((int32*)&info->next_qpair, 1) 300 % info->qpair_count]; 301 } 302 303 304 static void 305 disk_io_callback(status_t* status, const struct nvme_cpl* cpl) 306 { 307 *status = nvme_cpl_is_error(cpl) ? B_IO_ERROR : B_OK; 308 } 309 310 311 static void 312 await_status(struct nvme_qpair* qpair, status_t& status) 313 { 314 while (status == EINPROGRESS) { 315 // nvme_ioqp_poll uses locking internally on the entire device, 316 // not just this qpair, so it is entirely possible that it could 317 // return 0 (i.e. no completions processed) and yet our status 318 // changed, because some other thread processed the completion 319 // before we got to it. So, recheck it before sleeping. 320 if (nvme_ioqp_poll(qpair, 0) == 0 && status == EINPROGRESS) 321 snooze(5); 322 } 323 } 324 325 326 static status_t 327 do_nvme_io(nvme_disk_driver_info* info, off_t rounded_pos, void* buffer, 328 size_t* rounded_len, bool write = false) 329 { 330 CALLED(); 331 const size_t block_size = info->block_size; 332 333 status_t status = EINPROGRESS; 334 335 qpair_info* qpinfo = get_next_qpair(info); 336 mutex_lock(&qpinfo->mtx); 337 int ret = -1; 338 if (write) { 339 ret = nvme_ns_write(info->ns, qpinfo->qpair, buffer, 340 rounded_pos / block_size, *rounded_len / block_size, 341 (nvme_cmd_cb)disk_io_callback, &status, 0); 342 } else { 343 ret = nvme_ns_read(info->ns, qpinfo->qpair, buffer, 344 rounded_pos / block_size, *rounded_len / block_size, 345 (nvme_cmd_cb)disk_io_callback, &status, 0); 346 } 347 mutex_unlock(&qpinfo->mtx); 348 if (ret != 0) 349 return ret; 350 351 await_status(qpinfo->qpair, status); 352 353 if (status != B_OK) 354 *rounded_len = 0; 355 return status; 356 } 357 358 359 static status_t 360 do_nvme_segmented_io(nvme_disk_driver_info* info, off_t rounded_pos, 361 void* buffer, size_t* rounded_len, bool write = false) 362 { 363 // The max transfer size is already a multiple of the block size, 364 // so divide and iterate appropriately. In the case where the length 365 // is less than the maximum transfer size, we'll wind up with 0 in the 366 // division, and only one transfer to take care of. 367 const size_t max_xfer = info->max_transfer_size; 368 int32 transfers = *rounded_len / max_xfer; 369 if ((*rounded_len % max_xfer) != 0) 370 transfers++; 371 372 size_t transferred = 0; 373 for (int32 i = 0; i < transfers; i++) { 374 size_t transfer_len = max_xfer; 375 // The last transfer will usually be smaller. 376 if (i == (transfers - 1)) 377 transfer_len = *rounded_len - transferred; 378 379 status_t status = do_nvme_io(info, rounded_pos, buffer, 380 &transfer_len, write); 381 if (status != B_OK) { 382 *rounded_len = transferred; 383 return transferred > 0 ? (write ? B_PARTIAL_WRITE : B_PARTIAL_READ) 384 : status; 385 } 386 387 transferred += transfer_len; 388 rounded_pos += transfer_len; 389 buffer = ((int8*)buffer) + transfer_len; 390 } 391 return B_OK; 392 } 393 394 395 static status_t 396 nvme_disk_read(void* cookie, off_t pos, void* buffer, size_t* length) 397 { 398 CALLED(); 399 nvme_disk_handle* handle = (nvme_disk_handle*)cookie; 400 const size_t block_size = handle->info->block_size; 401 402 // libnvme does transfers in units of device sectors, so if we have to 403 // round either the position or the length, we will need a bounce buffer. 404 const off_t rounded_pos = ROUNDDOWN(pos, block_size); 405 size_t rounded_len = ROUNDUP((*length) + (pos - rounded_pos), block_size); 406 if (rounded_pos != pos || rounded_len != *length 407 || IS_USER_ADDRESS(buffer)) { 408 void* bounceBuffer = malloc(rounded_len); 409 MemoryDeleter _(bounceBuffer); 410 if (bounceBuffer == NULL) { 411 *length = 0; 412 return B_NO_MEMORY; 413 } 414 415 status_t status = nvme_disk_read(cookie, rounded_pos, bounceBuffer, 416 &rounded_len); 417 if (status != B_OK) { 418 // The "rounded_len" will be the actual transferred length, but 419 // of course it will contain the padding. 420 *length = std::min(*length, std::max((size_t)0, 421 rounded_len - (size_t)(pos - rounded_pos))); 422 if (*length == 0) 423 return status; 424 } 425 426 void* offsetBuffer = ((int8*)bounceBuffer) + (pos - rounded_pos); 427 if (IS_USER_ADDRESS(buffer)) 428 status = user_memcpy(buffer, offsetBuffer, *length); 429 else 430 memcpy(buffer, offsetBuffer, *length); 431 return status; 432 } 433 434 // If we got here, that means the arguments are already rounded to LBAs, 435 // so just do the I/O directly. 436 return do_nvme_segmented_io(handle->info, pos, buffer, length); 437 } 438 439 440 static status_t 441 nvme_disk_write(void* cookie, off_t pos, const void* buffer, size_t* length) 442 { 443 CALLED(); 444 nvme_disk_handle* handle = (nvme_disk_handle*)cookie; 445 const size_t block_size = handle->info->block_size; 446 447 const off_t rounded_pos = ROUNDDOWN(pos, block_size); 448 size_t rounded_len = ROUNDUP((*length) + (pos - rounded_pos), block_size); 449 if (rounded_pos != pos || rounded_len != *length 450 || IS_USER_ADDRESS(buffer)) { 451 void* bounceBuffer = malloc(rounded_len); 452 MemoryDeleter _(bounceBuffer); 453 if (bounceBuffer == NULL) { 454 *length = 0; 455 return B_NO_MEMORY; 456 } 457 458 // Since we rounded, we need to read in the first and last logical 459 // blocks before we copy our information to the bounce buffer. 460 // TODO: This would be faster if we queued both reads at once! 461 size_t readlen = block_size; 462 status_t status = do_nvme_io(handle->info, rounded_pos, bounceBuffer, 463 &readlen); 464 if (status != B_OK) { 465 *length = 0; 466 return status; 467 } 468 if (rounded_len > block_size) { 469 off_t offset = rounded_len - block_size; 470 status = do_nvme_io(handle->info, rounded_pos + offset, 471 ((int8*)bounceBuffer) + offset, &readlen); 472 if (status != B_OK) { 473 *length = 0; 474 return status; 475 } 476 } 477 478 void* offsetBuffer = ((int8*)bounceBuffer) + (pos - rounded_pos); 479 if (IS_USER_ADDRESS(buffer)) 480 status = user_memcpy(offsetBuffer, buffer, *length); 481 else 482 memcpy(offsetBuffer, buffer, *length); 483 if (status != B_OK) { 484 *length = 0; 485 return status; 486 } 487 488 status = nvme_disk_write(cookie, rounded_pos, bounceBuffer, 489 &rounded_len); 490 if (status != B_OK) { 491 *length = std::min(*length, std::max((size_t)0, 492 rounded_len - (size_t)(pos - rounded_pos))); 493 } 494 return status; 495 } 496 497 // If we got here, that means the arguments are already rounded to LBAs, 498 // so just do the I/O directly. 499 return do_nvme_segmented_io(handle->info, pos, (void*)buffer, length, true); 500 } 501 502 503 static status_t 504 nvme_disk_flush(nvme_disk_driver_info* info) 505 { 506 status_t status = EINPROGRESS; 507 508 qpair_info* qpinfo = get_next_qpair(info); 509 mutex_lock(&qpinfo->mtx); 510 int ret = nvme_ns_flush(info->ns, qpinfo->qpair, 511 (nvme_cmd_cb)disk_io_callback, &status); 512 mutex_unlock(&qpinfo->mtx); 513 if (ret != 0) 514 return ret; 515 516 await_status(qpinfo->qpair, status); 517 return status; 518 } 519 520 521 static status_t 522 nvme_disk_ioctl(void* cookie, uint32 op, void* buffer, size_t length) 523 { 524 CALLED(); 525 nvme_disk_handle* handle = (nvme_disk_handle*)cookie; 526 nvme_disk_driver_info* info = handle->info; 527 528 TRACE("ioctl(op = %" B_PRId32 ")\n", op); 529 530 switch (op) { 531 case B_GET_MEDIA_STATUS: 532 { 533 *(status_t *)buffer = info->media_status; 534 info->media_status = B_OK; 535 return B_OK; 536 break; 537 } 538 539 case B_GET_DEVICE_SIZE: 540 { 541 size_t size = info->capacity * info->block_size; 542 return user_memcpy(buffer, &size, sizeof(size_t)); 543 } 544 545 case B_GET_GEOMETRY: 546 { 547 if (buffer == NULL /*|| length != sizeof(device_geometry)*/) 548 return B_BAD_VALUE; 549 550 device_geometry geometry; 551 status_t status = get_geometry(handle, &geometry); 552 if (status != B_OK) 553 return status; 554 555 return user_memcpy(buffer, &geometry, sizeof(device_geometry)); 556 } 557 558 case B_GET_ICON_NAME: 559 return user_strlcpy((char*)buffer, "devices/drive-harddisk", 560 B_FILE_NAME_LENGTH); 561 562 case B_GET_VECTOR_ICON: 563 { 564 device_icon iconData; 565 if (length != sizeof(device_icon)) 566 return B_BAD_VALUE; 567 if (user_memcpy(&iconData, buffer, sizeof(device_icon)) != B_OK) 568 return B_BAD_ADDRESS; 569 570 if (iconData.icon_size >= (int32)sizeof(kDriveIcon)) { 571 if (user_memcpy(iconData.icon_data, kDriveIcon, 572 sizeof(kDriveIcon)) != B_OK) 573 return B_BAD_ADDRESS; 574 } 575 576 iconData.icon_size = sizeof(kDriveIcon); 577 return user_memcpy(buffer, &iconData, sizeof(device_icon)); 578 } 579 580 case B_FLUSH_DRIVE_CACHE: 581 return nvme_disk_flush(info); 582 } 583 584 return B_DEV_INVALID_IOCTL; 585 } 586 587 588 // #pragma mark - driver module API 589 590 591 static float 592 nvme_disk_supports_device(device_node *parent) 593 { 594 CALLED(); 595 596 const char* bus; 597 uint16 baseClass, subClass; 598 599 if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false) != B_OK 600 || sDeviceManager->get_attr_uint16(parent, B_DEVICE_TYPE, &baseClass, false) != B_OK 601 || sDeviceManager->get_attr_uint16(parent, B_DEVICE_SUB_TYPE, &subClass, false) != B_OK) 602 return -1.0f; 603 604 if (strcmp(bus, "pci") != 0 || baseClass != PCI_mass_storage) 605 return 0.0f; 606 607 if (subClass != PCI_nvm) 608 return 0.0f; 609 610 TRACE("NVMe device found!\n"); 611 return 1.0f; 612 } 613 614 615 static status_t 616 nvme_disk_register_device(device_node* parent) 617 { 618 CALLED(); 619 620 device_attr attrs[] = { 621 { NULL } 622 }; 623 624 return sDeviceManager->register_node(parent, NVME_DISK_DRIVER_MODULE_NAME, 625 attrs, NULL, NULL); 626 } 627 628 629 static status_t 630 nvme_disk_init_driver(device_node* node, void** cookie) 631 { 632 CALLED(); 633 634 int ret = nvme_lib_init((enum nvme_log_level)0, (enum nvme_log_facility)0, NULL); 635 if (ret != 0) { 636 TRACE_ERROR("libnvme initialization failed!\n"); 637 return ret; 638 } 639 640 nvme_disk_driver_info* info = (nvme_disk_driver_info*)malloc( 641 sizeof(nvme_disk_driver_info)); 642 if (info == NULL) 643 return B_NO_MEMORY; 644 645 memset(info, 0, sizeof(*info)); 646 647 info->media_status = B_OK; 648 info->node = node; 649 650 *cookie = info; 651 return B_OK; 652 } 653 654 655 static void 656 nvme_disk_uninit_driver(void* _cookie) 657 { 658 CALLED(); 659 660 nvme_disk_driver_info* info = (nvme_disk_driver_info*)_cookie; 661 free(info); 662 } 663 664 665 static status_t 666 nvme_disk_register_child_devices(void* _cookie) 667 { 668 CALLED(); 669 670 nvme_disk_driver_info* info = (nvme_disk_driver_info*)_cookie; 671 status_t status; 672 673 int32 id = sDeviceManager->create_id(NVME_DISK_DEVICE_ID_GENERATOR); 674 if (id < 0) 675 return id; 676 677 char name[64]; 678 snprintf(name, sizeof(name), "disk/nvme/%" B_PRId32 "/raw", 679 id); 680 681 status = sDeviceManager->publish_device(info->node, name, 682 NVME_DISK_DEVICE_MODULE_NAME); 683 684 return status; 685 } 686 687 688 // #pragma mark - 689 690 691 module_dependency module_dependencies[] = { 692 {B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&sDeviceManager}, 693 {} 694 }; 695 696 struct device_module_info sNvmeDiskDevice = { 697 { 698 NVME_DISK_DEVICE_MODULE_NAME, 699 0, 700 NULL 701 }, 702 703 nvme_disk_init_device, 704 nvme_disk_uninit_device, 705 NULL, // remove, 706 707 nvme_disk_open, 708 nvme_disk_close, 709 nvme_disk_free, 710 nvme_disk_read, 711 nvme_disk_write, 712 NULL, 713 nvme_disk_ioctl, 714 715 NULL, // select 716 NULL, // deselect 717 }; 718 719 struct driver_module_info sNvmeDiskDriver = { 720 { 721 NVME_DISK_DRIVER_MODULE_NAME, 722 0, 723 NULL 724 }, 725 726 nvme_disk_supports_device, 727 nvme_disk_register_device, 728 nvme_disk_init_driver, 729 nvme_disk_uninit_driver, 730 nvme_disk_register_child_devices, 731 NULL, // rescan 732 NULL, // removed 733 }; 734 735 module_info* modules[] = { 736 (module_info*)&sNvmeDiskDriver, 737 (module_info*)&sNvmeDiskDevice, 738 NULL 739 }; 740