// returns the number of blocks where the write was not successful. static ssize_t write_test(bdev_t *device) { uint8_t *test_buffer = memalign(DMA_ALIGNMENT, device->block_size); for (bnum_t bnum = 0; bnum < device->block_count; bnum++) { memset(test_buffer, get_signature(bnum), device->block_size); ssize_t err = bio_write_block(device, test_buffer, bnum, 1); if (err < 0) { free(test_buffer); return err; } } size_t num_errors = 0; uint8_t expected_pattern[1]; for (bnum_t bnum = 0; bnum < device->block_count; bnum++) { expected_pattern[0] = get_signature(bnum); if (!is_valid_block(device, bnum, expected_pattern, sizeof(expected_pattern))) { num_errors++; } } free(test_buffer); return num_errors; }
static bool test_erase_block(bdev_t *device, uint32_t block_addr) { bool success = false; uint8_t valid_byte[1]; uint8_t *block_contents = memalign(DMA_ALIGNMENT, device->block_size); memset(block_contents, ~(device->erase_byte), device->block_size); ssize_t err = bio_write_block(device, block_contents, block_addr, 1); if (err != (ssize_t)device->block_size) { goto finish; } valid_byte[0] = ~(device->erase_byte); if (!is_valid_block(device, block_addr, valid_byte, 1)) { goto finish; } err = bio_erase(device, block_addr * device->block_size, 1); if (err <= 0) { goto finish; } valid_byte[0] = device->erase_byte; if (is_valid_block(device, block_addr, valid_byte, 1)) { success = true; } finish: free(block_contents); return success; }
static ssize_t subdev_write_block(struct bdev *_dev, const void *buf, bnum_t block, uint count) { subdev_t *subdev = (subdev_t *)_dev; return bio_write_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; }