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 79 struct nvme_ns* ns; 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 TRACE_ERROR("attempt to queue %s I/O at %" B_PRIdOFF " of %" B_PRIuSIZE 350 " bytes failed!", write ? "write" : "read", rounded_pos, *rounded_len); 351 return ret; 352 } 353 354 await_status(qpinfo->qpair, status); 355 356 if (status != B_OK) { 357 TRACE_ERROR("%s at %" B_PRIdOFF " of %" B_PRIuSIZE " bytes failed!", 358 write ? "write" : "read", rounded_pos, *rounded_len); 359 *rounded_len = 0; 360 } 361 return status; 362 } 363 364 365 static status_t 366 do_nvme_segmented_io(nvme_disk_driver_info* info, off_t rounded_pos, 367 void* buffer, size_t* rounded_len, bool write = false) 368 { 369 // The max transfer size is already a multiple of the block size, 370 // so divide and iterate appropriately. In the case where the length 371 // is less than the maximum transfer size, we'll wind up with 0 in the 372 // division, and only one transfer to take care of. 373 const size_t max_xfer = info->max_transfer_size; 374 int32 transfers = *rounded_len / max_xfer; 375 if ((*rounded_len % max_xfer) != 0) 376 transfers++; 377 378 size_t transferred = 0; 379 for (int32 i = 0; i < transfers; i++) { 380 size_t transfer_len = max_xfer; 381 // The last transfer will usually be smaller. 382 if (i == (transfers - 1)) 383 transfer_len = *rounded_len - transferred; 384 385 status_t status = do_nvme_io(info, rounded_pos, buffer, 386 &transfer_len, write); 387 if (status != B_OK) { 388 *rounded_len = transferred; 389 return transferred > 0 ? (write ? B_PARTIAL_WRITE : B_PARTIAL_READ) 390 : status; 391 } 392 393 transferred += transfer_len; 394 rounded_pos += transfer_len; 395 buffer = ((int8*)buffer) + transfer_len; 396 } 397 return B_OK; 398 } 399 400 401 static status_t 402 nvme_disk_read(void* cookie, off_t pos, void* buffer, size_t* length) 403 { 404 CALLED(); 405 nvme_disk_handle* handle = (nvme_disk_handle*)cookie; 406 const size_t block_size = handle->info->block_size; 407 408 // libnvme does transfers in units of device sectors, so if we have to 409 // round either the position or the length, we will need a bounce buffer. 410 const off_t rounded_pos = ROUNDDOWN(pos, block_size); 411 size_t rounded_len = ROUNDUP((*length) + (pos - rounded_pos), block_size); 412 if (rounded_pos != pos || rounded_len != *length 413 || IS_USER_ADDRESS(buffer)) { 414 void* bounceBuffer = malloc(rounded_len); 415 MemoryDeleter _(bounceBuffer); 416 if (bounceBuffer == NULL) { 417 *length = 0; 418 return B_NO_MEMORY; 419 } 420 421 status_t status = do_nvme_segmented_io(handle->info, rounded_pos, 422 bounceBuffer, &rounded_len); 423 if (status != B_OK) { 424 // The "rounded_len" will be the actual transferred length, but 425 // of course it will contain the padding. 426 *length = std::min(*length, (size_t)std::max((off_t)0, 427 (off_t)rounded_len - (off_t)(pos - rounded_pos))); 428 if (*length == 0) 429 return status; 430 } 431 432 void* offsetBuffer = ((int8*)bounceBuffer) + (pos - rounded_pos); 433 if (IS_USER_ADDRESS(buffer)) 434 status = user_memcpy(buffer, offsetBuffer, *length); 435 else 436 memcpy(buffer, offsetBuffer, *length); 437 return status; 438 } 439 440 // If we got here, that means the arguments are already rounded to LBAs 441 // and the buffer is a kernel one, so just do the I/O directly. 442 return do_nvme_segmented_io(handle->info, pos, buffer, length); 443 } 444 445 446 static status_t 447 nvme_disk_write(void* cookie, off_t pos, const void* buffer, size_t* length) 448 { 449 CALLED(); 450 nvme_disk_handle* handle = (nvme_disk_handle*)cookie; 451 const size_t block_size = handle->info->block_size; 452 453 const off_t rounded_pos = ROUNDDOWN(pos, block_size); 454 size_t rounded_len = ROUNDUP((*length) + (pos - rounded_pos), block_size); 455 if (rounded_pos != pos || rounded_len != *length 456 || IS_USER_ADDRESS(buffer)) { 457 void* bounceBuffer = malloc(rounded_len); 458 MemoryDeleter _(bounceBuffer); 459 if (bounceBuffer == NULL) { 460 *length = 0; 461 return B_NO_MEMORY; 462 } 463 464 // Since we rounded, we need to read in the first and last logical 465 // blocks before we copy our information to the bounce buffer. 466 // TODO: This would be faster if we queued both reads at once! 467 size_t readlen = block_size; 468 status_t status; 469 if (rounded_pos != pos) { 470 status = do_nvme_io(handle->info, rounded_pos, bounceBuffer, 471 &readlen); 472 if (status != B_OK) { 473 *length = 0; 474 return status; 475 } 476 } 477 if (rounded_len > block_size) { 478 off_t offset = rounded_len - block_size; 479 status = do_nvme_io(handle->info, rounded_pos + offset, 480 ((int8*)bounceBuffer) + offset, &readlen); 481 if (status != B_OK) { 482 *length = 0; 483 return status; 484 } 485 } 486 487 // Now we can copy in the actual data to be written. 488 void* offsetBuffer = ((int8*)bounceBuffer) + (pos - rounded_pos); 489 if (IS_USER_ADDRESS(buffer)) 490 status = user_memcpy(offsetBuffer, buffer, *length); 491 else 492 memcpy(offsetBuffer, buffer, *length); 493 if (status != B_OK) { 494 *length = 0; 495 return status; 496 } 497 498 status = do_nvme_segmented_io(handle->info, rounded_pos, bounceBuffer, 499 &rounded_len, true); 500 if (status != B_OK) { 501 *length = std::min(*length, (size_t)std::max((off_t)0, 502 (off_t)rounded_len - (off_t)(pos - rounded_pos))); 503 } 504 return status; 505 } 506 507 // If we got here, that means the arguments are already rounded to LBAs, 508 // so just do the I/O directly. 509 return do_nvme_segmented_io(handle->info, pos, (void*)buffer, length, true); 510 } 511 512 513 static status_t 514 nvme_disk_flush(nvme_disk_driver_info* info) 515 { 516 status_t status = EINPROGRESS; 517 518 qpair_info* qpinfo = get_next_qpair(info); 519 mutex_lock(&qpinfo->mtx); 520 int ret = nvme_ns_flush(info->ns, qpinfo->qpair, 521 (nvme_cmd_cb)disk_io_callback, &status); 522 mutex_unlock(&qpinfo->mtx); 523 if (ret != 0) 524 return ret; 525 526 await_status(qpinfo->qpair, status); 527 return status; 528 } 529 530 531 static status_t 532 nvme_disk_ioctl(void* cookie, uint32 op, void* buffer, size_t length) 533 { 534 CALLED(); 535 nvme_disk_handle* handle = (nvme_disk_handle*)cookie; 536 nvme_disk_driver_info* info = handle->info; 537 538 TRACE("ioctl(op = %" B_PRId32 ")\n", op); 539 540 switch (op) { 541 case B_GET_MEDIA_STATUS: 542 { 543 *(status_t *)buffer = info->media_status; 544 info->media_status = B_OK; 545 return B_OK; 546 break; 547 } 548 549 case B_GET_DEVICE_SIZE: 550 { 551 size_t size = info->capacity * info->block_size; 552 return user_memcpy(buffer, &size, sizeof(size_t)); 553 } 554 555 case B_GET_GEOMETRY: 556 { 557 if (buffer == NULL /*|| length != sizeof(device_geometry)*/) 558 return B_BAD_VALUE; 559 560 device_geometry geometry; 561 status_t status = get_geometry(handle, &geometry); 562 if (status != B_OK) 563 return status; 564 565 return user_memcpy(buffer, &geometry, sizeof(device_geometry)); 566 } 567 568 case B_GET_ICON_NAME: 569 return user_strlcpy((char*)buffer, "devices/drive-harddisk", 570 B_FILE_NAME_LENGTH); 571 572 case B_GET_VECTOR_ICON: 573 { 574 device_icon iconData; 575 if (length != sizeof(device_icon)) 576 return B_BAD_VALUE; 577 if (user_memcpy(&iconData, buffer, sizeof(device_icon)) != B_OK) 578 return B_BAD_ADDRESS; 579 580 if (iconData.icon_size >= (int32)sizeof(kDriveIcon)) { 581 if (user_memcpy(iconData.icon_data, kDriveIcon, 582 sizeof(kDriveIcon)) != B_OK) 583 return B_BAD_ADDRESS; 584 } 585 586 iconData.icon_size = sizeof(kDriveIcon); 587 return user_memcpy(buffer, &iconData, sizeof(device_icon)); 588 } 589 590 case B_FLUSH_DRIVE_CACHE: 591 return nvme_disk_flush(info); 592 } 593 594 return B_DEV_INVALID_IOCTL; 595 } 596 597 598 // #pragma mark - driver module API 599 600 601 static float 602 nvme_disk_supports_device(device_node *parent) 603 { 604 CALLED(); 605 606 const char* bus; 607 uint16 baseClass, subClass; 608 609 if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false) != B_OK 610 || sDeviceManager->get_attr_uint16(parent, B_DEVICE_TYPE, &baseClass, false) != B_OK 611 || sDeviceManager->get_attr_uint16(parent, B_DEVICE_SUB_TYPE, &subClass, false) != B_OK) 612 return -1.0f; 613 614 if (strcmp(bus, "pci") != 0 || baseClass != PCI_mass_storage) 615 return 0.0f; 616 617 if (subClass != PCI_nvm) 618 return 0.0f; 619 620 TRACE("NVMe device found!\n"); 621 return 1.0f; 622 } 623 624 625 static status_t 626 nvme_disk_register_device(device_node* parent) 627 { 628 CALLED(); 629 630 device_attr attrs[] = { 631 { NULL } 632 }; 633 634 return sDeviceManager->register_node(parent, NVME_DISK_DRIVER_MODULE_NAME, 635 attrs, NULL, NULL); 636 } 637 638 639 static status_t 640 nvme_disk_init_driver(device_node* node, void** cookie) 641 { 642 CALLED(); 643 644 int ret = nvme_lib_init((enum nvme_log_level)0, (enum nvme_log_facility)0, NULL); 645 if (ret != 0) { 646 TRACE_ERROR("libnvme initialization failed!\n"); 647 return ret; 648 } 649 650 nvme_disk_driver_info* info = (nvme_disk_driver_info*)malloc( 651 sizeof(nvme_disk_driver_info)); 652 if (info == NULL) 653 return B_NO_MEMORY; 654 655 memset(info, 0, sizeof(*info)); 656 657 info->media_status = B_OK; 658 info->node = node; 659 660 *cookie = info; 661 return B_OK; 662 } 663 664 665 static void 666 nvme_disk_uninit_driver(void* _cookie) 667 { 668 CALLED(); 669 670 nvme_disk_driver_info* info = (nvme_disk_driver_info*)_cookie; 671 free(info); 672 } 673 674 675 static status_t 676 nvme_disk_register_child_devices(void* _cookie) 677 { 678 CALLED(); 679 680 nvme_disk_driver_info* info = (nvme_disk_driver_info*)_cookie; 681 status_t status; 682 683 int32 id = sDeviceManager->create_id(NVME_DISK_DEVICE_ID_GENERATOR); 684 if (id < 0) 685 return id; 686 687 char name[64]; 688 snprintf(name, sizeof(name), "disk/nvme/%" B_PRId32 "/raw", 689 id); 690 691 status = sDeviceManager->publish_device(info->node, name, 692 NVME_DISK_DEVICE_MODULE_NAME); 693 694 return status; 695 } 696 697 698 // #pragma mark - 699 700 701 module_dependency module_dependencies[] = { 702 {B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&sDeviceManager}, 703 {} 704 }; 705 706 struct device_module_info sNvmeDiskDevice = { 707 { 708 NVME_DISK_DEVICE_MODULE_NAME, 709 0, 710 NULL 711 }, 712 713 nvme_disk_init_device, 714 nvme_disk_uninit_device, 715 NULL, // remove, 716 717 nvme_disk_open, 718 nvme_disk_close, 719 nvme_disk_free, 720 nvme_disk_read, 721 nvme_disk_write, 722 NULL, 723 nvme_disk_ioctl, 724 725 NULL, // select 726 NULL, // deselect 727 }; 728 729 struct driver_module_info sNvmeDiskDriver = { 730 { 731 NVME_DISK_DRIVER_MODULE_NAME, 732 0, 733 NULL 734 }, 735 736 nvme_disk_supports_device, 737 nvme_disk_register_device, 738 nvme_disk_init_driver, 739 nvme_disk_uninit_driver, 740 nvme_disk_register_child_devices, 741 NULL, // rescan 742 NULL, // removed 743 }; 744 745 module_info* modules[] = { 746 (module_info*)&sNvmeDiskDriver, 747 (module_info*)&sNvmeDiskDevice, 748 NULL 749 }; 750