static ssize_t subdev_read_block(struct bdev *_dev, void *buf, bnum_t block, uint count) { subdev_t *subdev = (subdev_t *)_dev; return bio_read_block(subdev->parent, buf, block + subdev->offset, count); }
static status_t memory_mapped_test(bdev_t *device) { status_t retcode = NO_ERROR; uint8_t *test_buffer = memalign(DMA_ALIGNMENT, device->block_size); if (!test_buffer) { printf("Could not allocate %zu bytes for a temporary buffer. " "Aborting.\n", device->block_size); return ERR_NO_MEMORY; } uint8_t *reference_buffer = memalign(DMA_ALIGNMENT, device->block_size); if (!reference_buffer) { printf("Could not allocate %zu bytes for a temporary reference " "buffer. Aborting.\n", device->block_size); free(test_buffer); return ERR_NO_MEMORY; } // Erase the first page of the Device. ssize_t err = bio_erase(device, 0, device->block_size); if (err < (ssize_t)device->block_size) { printf("Expected to erase at least %zu bytes but only erased %ld. " "Not continuing to test memory mapped mode.\n", device->block_size, err); retcode = ERR_IO; goto finish; } // Write a pattern to the first page of the device. uint8_t pattern_seed = (uint8_t)(rand() % 256); for (size_t i = 0; i < device->block_size; i++) { test_buffer[i] = (uint8_t)((pattern_seed + i) % 256); } err = bio_write_block(device, test_buffer, 0, 1); if (err != (ssize_t)device->block_size) { printf("Error while writing test pattern to device. Expected to write " "%zu bytes but actually wrote %ld. Not continuing to test memory " "mapped mode.\n", device->block_size, err); retcode = ERR_IO; goto finish; } // Put the device into linear mode if possible. uint8_t *devaddr; int ioctl_result = bio_ioctl(device, BIO_IOCTL_GET_MEM_MAP, (void *)&devaddr); if (ioctl_result == ERR_NOT_SUPPORTED) { printf("Device does not support linear mode. Aborting.\n"); retcode = ERR_NOT_SUPPORTED; goto finish; } else if (ioctl_result != NO_ERROR) { printf("BIO_IOCTL_GET_MEM_MAP returned error %d. Aborting.\n", ioctl_result); retcode = ioctl_result; goto finish; } uint8_t *testptr = test_buffer; for (uint i = 0; i < device->block_size; i++) { if (*testptr != *devaddr) { printf("Data mismatch at position %d. Expected %d got %d. " "Aborting.\n", i, *testptr, *devaddr); goto finish; } testptr++; devaddr++; } // Put the device back into command mode. ioctl_result = bio_ioctl(device, BIO_IOCTL_PUT_MEM_MAP, NULL); if (ioctl_result != NO_ERROR) { printf("BIO_IOCTL_GET_MEM_MAP returned error %d. Aborting.\n", ioctl_result); retcode = ioctl_result; goto finish; } // Read the first page into memory using command mode and compare it with // what we wrote back earlier. err = bio_read_block(device, reference_buffer, 0, 1); if (err != (ssize_t)device->block_size) { printf("Expected to read %zu bytes, actually read %ld. Aborting.\n", device->block_size, err); retcode = ERR_IO; goto finish; } uint8_t *expected = test_buffer; uint8_t *actual = reference_buffer; for (uint i = 0; i < device->block_size; i++) { if (*actual != *expected) { printf("Data mismatch at position %d. Expected %d got %d. " "Aborting.\n", i, *expected, *actual); goto finish; } expected++; actual++; } finish: free(test_buffer); free(reference_buffer); return retcode; }