/* * blkio_usb.c — USB Mass Storage (Bulk-Only Transport) blkio_dev backend, * see blkio_usb.h. Milestone 2h. */ #ifndef __STARKERNEL__ #error "blkio_usb.c is kernel-only" #endif #include #include #include #include "starkernel/blkio_usb.h" #include "console.h" typedef struct { xhci_dev_t *xdev; uint32_t slot_id; uint32_t scsi_block_size; uint32_t scsi_blocks_per_fblock; /* BLKIO_FORTH_BLOCK_SIZE / scsi_block_size */ uint32_t total_forth_blocks; } BlkioUsbState; /* Singleton — one USB MSC device (single-outstanding-transaction scope, * matching the xHCI driver this backend sits on). */ static BlkioUsbState g_usb_blk; static int usb_blk_open(blkio_dev_t *dev, const blkio_params_t *p) { (void)p; if (!dev) return BLKIO_EINVAL; dev->state = &g_usb_blk; dev->forth_block_size = BLKIO_FORTH_BLOCK_SIZE; dev->total_blocks = g_usb_blk.total_forth_blocks; return BLKIO_OK; } static int usb_blk_close(blkio_dev_t *dev) { (void)dev; return BLKIO_OK; } static int usb_blk_read(blkio_dev_t *dev, uint32_t fblock, void *dst) { if (!dev || !dst) return BLKIO_EINVAL; BlkioUsbState *s = (BlkioUsbState *)dev->state; if (fblock >= s->total_forth_blocks) return BLKIO_EINVAL; uint32_t lba = fblock * s->scsi_blocks_per_fblock; if (xhci_bot_read_block(s->xdev, s->slot_id, lba, (uint16_t)s->scsi_blocks_per_fblock, s->scsi_block_size) != 0) { return BLKIO_EIO; } if (xhci_bot_wait_for_idle(s->xdev, 100000u) != BOT_STATUS_PASS) { return BLKIO_EIO; } memcpy(dst, s->xdev->bot_data_buf, BLKIO_FORTH_BLOCK_SIZE); return BLKIO_OK; } static int usb_blk_write(blkio_dev_t *dev, uint32_t fblock, const void *src) { if (!dev || !src) return BLKIO_EINVAL; BlkioUsbState *s = (BlkioUsbState *)dev->state; if (fblock >= s->total_forth_blocks) return BLKIO_EINVAL; memcpy(s->xdev->bot_data_buf, src, BLKIO_FORTH_BLOCK_SIZE); uint32_t lba = fblock * s->scsi_blocks_per_fblock; if (xhci_bot_write_block(s->xdev, s->slot_id, lba, (uint16_t)s->scsi_blocks_per_fblock, s->scsi_block_size) != 0) { return BLKIO_EIO; } if (xhci_bot_wait_for_idle(s->xdev, 100000u) != BOT_STATUS_PASS) { return BLKIO_EIO; } return BLKIO_OK; } static int usb_blk_flush(blkio_dev_t *dev) { (void)dev; return BLKIO_OK; /* every write above is already synchronous -- see * usb_blk_write()'s own xhci_bot_wait_for_idle() * call -- nothing buffered here to flush. */ } static int usb_blk_info(blkio_dev_t *dev, blkio_info_t *out) { if (!dev || !out) return BLKIO_EINVAL; BlkioUsbState *s = (BlkioUsbState *)dev->state; out->forth_block_size = BLKIO_FORTH_BLOCK_SIZE; out->total_blocks = s->total_forth_blocks; out->phys_sector_size = s->scsi_block_size; out->phys_size_bytes = (uint64_t)s->total_forth_blocks * BLKIO_FORTH_BLOCK_SIZE; out->read_only = 0; /* WRITE(10) verified live end-to-end on amd64, * 2026-08-28 (FABRIC-2.md §F.1): BLK-CONFIRM-FORMAT's * BAM/reloc writes and an explicit content write both * survived a cold reboot and read back correctly. */ return BLKIO_OK; } static const blkio_vtable_t g_usb_blk_vtable = { .open = usb_blk_open, .close = usb_blk_close, .read = usb_blk_read, .write = usb_blk_write, .flush = usb_blk_flush, .info = usb_blk_info }; int blkio_usb_open_msc(blkio_dev_t *dev_out, xhci_dev_t *xdev, uint32_t slot_id) { if (!dev_out || !xdev) return -1; if (xhci_bot_get_capacity(xdev, slot_id) != 0) return -1; if (xhci_bot_wait_for_idle(xdev, 100000u) != BOT_STATUS_PASS) return -1; uint32_t block_size = xdev->bot_cap_block_size; if (block_size == 0 || (BLKIO_FORTH_BLOCK_SIZE % block_size) != 0) { console_println("blkio_usb: SCSI block size doesn't divide Forth block size -- refusing"); return -2; } uint64_t total_scsi_blocks = (uint64_t)xdev->bot_cap_last_lba + 1u; uint32_t blocks_per_fblock = BLKIO_FORTH_BLOCK_SIZE / block_size; uint64_t total_forth_blocks = total_scsi_blocks / blocks_per_fblock; g_usb_blk.xdev = xdev; g_usb_blk.slot_id = slot_id; g_usb_blk.scsi_block_size = block_size; g_usb_blk.scsi_blocks_per_fblock = blocks_per_fblock; g_usb_blk.total_forth_blocks = (total_forth_blocks > 0xFFFFFFFFull) ? 0xFFFFFFFFu : (uint32_t)total_forth_blocks; console_println("blkio_usb: MSC device ready"); blkio_params_t params; params.forth_block_size = BLKIO_FORTH_BLOCK_SIZE; params.total_blocks = g_usb_blk.total_forth_blocks; params.opaque = NULL; return blkio_open(dev_out, &g_usb_blk_vtable, ¶ms); }