Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/machine/usb/msc/disk.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ func (m *msc) RegisterBlockDevice(dev machine.BlockDevice) {
// them we assume the provided block device is aligned to the end of the underlying hardware block
// device and offset all reads/writes by the remaining bytes that don't make up a full block.
m.blockOffset = uint32(m.dev.Size()) % m.blockSizeUSB
// FIXME: Figure out what to do if the emulated write block size is larger than the erase block size

// Set VPD UNMAP fields
for i := range vpdPages {
Expand All @@ -46,10 +45,11 @@ func (m *msc) RegisterBlockDevice(dev machine.BlockDevice) {
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf

// We assume the block device is aligned to the end of the underlying block device
blockOffset := uint32(dev.EraseBlockSize()) % m.blockSizeUSB
eraseBlockOffset := uint32(dev.EraseBlockSize()) % m.blockSizeUSB
m.eraseBlockOffset = eraseBlockOffset
// Set the UGAVALID bit to indicate that the UNMAP GRANULARITY ALIGNMENT is valid
blockOffset |= 0x80000000
binary.BigEndian.PutUint32(vpdPages[i].Data[28:32], blockOffset)
eraseBlockOffset |= 0x80000000
binary.BigEndian.PutUint32(vpdPages[i].Data[28:32], eraseBlockOffset)
}
break
}
Expand Down
15 changes: 8 additions & 7 deletions src/machine/usb/msc/msc.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,14 @@ type msc struct {
cswBuf []byte // CSW response buffer
state mscState

maxLUN uint8 // Maximum Logical Unit Number (n-1 for n LUNs)
dev machine.BlockDevice
blockCount uint32 // Number of blocks in the device
blockOffset uint32 // Byte offset of the first block in the device for aligned writes
blockSizeUSB uint32 // Write block size as presented to the host over USB
blockSizeRaw uint32 // Write block size of the underlying device hardware
readOnly bool
maxLUN uint8 // Maximum Logical Unit Number (n-1 for n LUNs)
dev machine.BlockDevice
blockCount uint32 // Number of blocks in the device
blockOffset uint32 // Byte offset of the first block in the device for aligned writes
blockSizeUSB uint32 // Write block size as presented to the host over USB
blockSizeRaw uint32 // Write block size of the underlying device hardware
eraseBlockOffset uint32 // Number of USB blocks before the first full erase block in the device
readOnly bool

vendorID [8]byte // Max 8 ASCII characters
productID [16]byte // Max 16 ASCII characters
Expand Down
22 changes: 17 additions & 5 deletions src/machine/usb/msc/scsi_unmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@
type Error int

const (
errorLBAOutOfRange Error = iota
errorLBAOutOfRange Error = iota
errorEraseBlockMisaligned Error

Check failure on line 13 in src/machine/usb/msc/scsi_unmap.go

View workflow job for this annotation

GitHub Actions / assert-test-linux

missing init expr for errorEraseBlockMisaligned
)

func (e Error) Error() string {
switch e {
case errorLBAOutOfRange:
return "LBA out of range"
case errorEraseBlockMisaligned:
return "Erase attempted on partial erase block"
default:
return "unknown error"
}
Expand Down Expand Up @@ -49,7 +52,7 @@

// Unmap the blocks we can from this packet
for i := 8; i < descEnd; i += 16 {
err := m.unmapBlocksFromDescriptor(b[i:], uint64(m.blockCount))
err := m.unmapBlocksFromDescriptor(b[i:])
if err != nil {
// TODO: Might need a better error code here for device errors?
m.sendScsiError(csw.StatusFailed, scsi.SenseVolumeOverflow, scsi.SenseCodeLBAOutOfRange)
Expand All @@ -67,7 +70,7 @@
}
}

func (m *msc) unmapBlocksFromDescriptor(b []byte, numBlocks uint64) error {
func (m *msc) unmapBlocksFromDescriptor(b []byte) error {
blockCount := binary.BigEndian.Uint32(b[8:12])
if blockCount == 0 {
// No blocks to unmap. Explicitly not an error per the spec
Expand All @@ -82,9 +85,18 @@
return errorLBAOutOfRange
}

return m.unmapUSBBlocks(lba, blockCount)
}

func (m *msc) unmapUSBBlocks(firstBlock, numBlocks uint32) error {
if firstBlock%m.blockSizeUSB != m.eraseBlockOffset {
// The starting block is not aligned to the underlying hardware erase block
return errorEraseBlockMisaligned
}

// Convert the emulated block size to the underlying hardware erase block size
blockStart := int64(lba*m.blockSizeUSB) / m.dev.EraseBlockSize()
rawBlockCount := int64(blockCount*m.blockSizeUSB) / m.dev.EraseBlockSize()
blockStart := int64(firstBlock*m.blockSizeUSB) / m.dev.EraseBlockSize()
rawBlockCount := int64(numBlocks*m.blockSizeUSB) / m.dev.EraseBlockSize()

// Unmap the blocks
return m.dev.EraseBlocks(blockStart, rawBlockCount)
Expand Down
Loading