Skip to content

Commit a1ce6ba

Browse files
committed
fix: correct errors using machine.flash
1 parent d5bc91c commit a1ce6ba

File tree

5 files changed

+141
-110
lines changed

5 files changed

+141
-110
lines changed

src/machine/usb/msc/disk.go

Lines changed: 45 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"errors"
66
"fmt"
77
"machine"
8-
"runtime/interrupt"
98
"time"
109
)
1110

@@ -17,14 +16,17 @@ var (
1716
func (m *msc) RegisterBlockDevice(dev machine.BlockDevice) {
1817
m.dev = dev
1918

20-
m.blockRatio = 1
21-
m.blockSize = uint32(m.dev.WriteBlockSize())
22-
if m.blockSize < 512 {
23-
// If the block size is less than 512 bytes, we'll scale it up to 512 for compatibility
24-
m.blockRatio = 512 / m.blockSize
25-
m.blockSize = 512
19+
if cap(m.blockCache) != int(dev.WriteBlockSize()) {
20+
m.blockCache = make([]byte, dev.WriteBlockSize())
21+
m.buf = make([]byte, dev.WriteBlockSize())
2622
}
27-
m.blockCount = uint32(m.dev.Size()) / m.blockSize
23+
24+
m.blockSizeRaw = uint32(m.dev.WriteBlockSize())
25+
m.blockCount = uint32(m.dev.Size()) / m.blockSizeUSB
26+
// Read/write/erase operations must be aligned to the underlying hardware blocks. In order to align
27+
// them we assume the provided block device is aligned to the end of the underlying hardware block
28+
// device and offset all reads/writes by the remaining bytes that don't make up a full block.
29+
m.blockOffset = uint32(m.dev.Size()) % m.blockSizeUSB
2830
// FIXME: Figure out what to do if the emulated write block size is larger than the erase block size
2931

3032
// Set VPD UNMAP fields
@@ -33,7 +35,7 @@ func (m *msc) RegisterBlockDevice(dev machine.BlockDevice) {
3335
// 0xb0 - 5.4.5 Block Limits VPD page (B0h)
3436
if len(vpdPages[i].Data) >= 28 {
3537
// Set the OPTIMAL UNMAP GRANULARITY (write blocks per erase block)
36-
granularity := uint32(dev.EraseBlockSize()) / m.blockSize
38+
granularity := uint32(dev.EraseBlockSize()) / m.blockSizeUSB
3739
binary.BigEndian.PutUint32(vpdPages[i].Data[24:28], granularity)
3840
}
3941
if len(vpdPages[i].Data) >= 32 {
@@ -44,7 +46,7 @@ func (m *msc) RegisterBlockDevice(dev machine.BlockDevice) {
4446
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
4547

4648
// We assume the block device is aligned to the end of the underlying block device
47-
blockOffset := uint32(dev.EraseBlockSize()) % m.blockSize
49+
blockOffset := uint32(dev.EraseBlockSize()) % m.blockSizeUSB
4850
binary.BigEndian.PutUint32(vpdPages[i].Data[28:32], blockOffset)
4951
}
5052
break
@@ -56,7 +58,7 @@ var _ machine.BlockDevice = (*RecorderDisk)(nil)
5658

5759
// RecorderDisk is a block device that records actions taken on it
5860
type RecorderDisk struct {
59-
data map[int64][]byte
61+
dev machine.BlockDevice
6062
log []RecorderRecord
6163
last time.Time
6264
time time.Time
@@ -80,9 +82,9 @@ const (
8082
)
8183

8284
// NewRecorderDisk creates a new RecorderDisk instance
83-
func NewRecorderDisk(count int) *RecorderDisk {
85+
func NewRecorderDisk(dev machine.BlockDevice, count int) *RecorderDisk {
8486
d := &RecorderDisk{
85-
data: make(map[int64][]byte),
87+
dev: dev,
8688
log: make([]RecorderRecord, 0, count),
8789
last: time.Now(),
8890
}
@@ -91,95 +93,64 @@ func NewRecorderDisk(count int) *RecorderDisk {
9193
OpCode: RecorderOpCodeRead,
9294
Offset: 0,
9395
Length: 0,
94-
Data: make([]byte, 0, 64),
96+
Data: make([]byte, dev.WriteBlockSize()),
9597
Time: 0,
9698
})
9799
}
98100
return d
99101
}
100102

101103
func (d *RecorderDisk) Size() int64 {
102-
return 4096 * int64(d.WriteBlockSize()) // 2MB
104+
return d.dev.Size()
103105
}
104106

105107
func (d *RecorderDisk) WriteBlockSize() int64 {
106-
return 512 // 512 bytes
108+
return d.dev.WriteBlockSize()
107109
}
108110

109111
func (d *RecorderDisk) EraseBlockSize() int64 {
110-
return 2048 // 4 blocks of 512 bytes
112+
return d.dev.EraseBlockSize()
111113
}
112114

113115
func (d *RecorderDisk) EraseBlocks(startBlock, numBlocks int64) error {
114116
d.Record(RecorderOpCodeEraseBlocks, startBlock, int(numBlocks), []byte{})
115-
if interrupt.In() {
116-
// Flash erase commands are not allowed in interrupt context
117-
panic("EraseBlocks attempted in interrupt context")
118-
}
119-
return nil
117+
return d.dev.EraseBlocks(startBlock, numBlocks)
120118
}
121119

122120
func (d *RecorderDisk) ReadAt(buffer []byte, offset int64) (int, error) {
123-
d.Record(RecorderOpCodeRead, offset, len(buffer), []byte{})
124-
sector := offset / d.WriteBlockSize()
125-
if sector < 0 || offset+int64(len(buffer)) > d.Size() {
126-
return 0, fmt.Errorf("read out of bounds: %d", offset)
127-
}
128-
129-
sectorCount := int64(len(buffer)) / d.WriteBlockSize()
130-
for i := int64(0); i < sectorCount; i++ {
131-
if _, ok := d.data[sector+i]; ok {
132-
n := int(offset % d.WriteBlockSize())
133-
copy(buffer, d.data[sector+i][n:])
134-
}
135-
}
136-
137-
return len(buffer), nil
121+
n, err := d.dev.ReadAt(buffer, offset)
122+
d.Record(RecorderOpCodeRead, offset, n, buffer)
123+
return n, err
138124
}
139125

140126
func (d *RecorderDisk) WriteAt(buffer []byte, offset int64) (int, error) {
141-
if interrupt.In() {
142-
// Flash writes aren't possible in interrupt context
143-
panic("WriteAt attempted in interrupt context")
144-
}
145-
if offset < 0 || offset+int64(len(buffer)) > d.Size() {
146-
return 0, errWriteOutOfBounds
147-
}
148-
149-
d.Record(RecorderOpCodeWrite, offset, len(buffer), buffer)
150-
151-
sector := offset / d.WriteBlockSize()
152-
sectorCount := int64(len(buffer)) / d.WriteBlockSize()
153-
for i := int64(0); i < sectorCount; i++ {
154-
_, ok := d.data[sector+i]
155-
if !ok {
156-
d.data[sector+i] = make([]byte, d.WriteBlockSize())
157-
}
158-
n := int(offset % d.WriteBlockSize())
159-
copy(d.data[sector+i][n:], buffer)
160-
}
161-
return len(buffer), nil
127+
n, err := d.dev.WriteAt(buffer, offset)
128+
d.Record(RecorderOpCodeWrite, offset, n, buffer)
129+
return n, err
162130
}
163131

164132
func (d *RecorderDisk) Record(opCode RecorderOpCode, offset int64, length int, data []byte) {
165-
n := len(d.log)
166-
if n == 0 {
167-
return
168-
} else if n == cap(d.log) {
169-
for i := 0; i < n-1; i++ {
170-
d.log[i] = d.log[i+1]
171-
}
133+
n := len(d.log) - 1
134+
// Shift the log entries up to make room for a new entry
135+
for i := 0; i < n; i++ {
136+
d.log[i].OpCode = d.log[i+1].OpCode
137+
d.log[i].Offset = d.log[i+1].Offset
138+
d.log[i].Length = d.log[i+1].Length
139+
d.log[i].Data = d.log[i].Data[:len(d.log[i+1].Data)]
140+
copy(d.log[i].Data, d.log[i+1].Data)
141+
d.log[i].Time = d.log[i+1].Time
142+
d.log[i].valid = d.log[i+1].valid
172143
}
173144

174145
// Append the new record
175-
d.log[n-1].OpCode = opCode
176-
d.log[n-1].Offset = offset
177-
d.log[n-1].Length = length
178-
d.log[n-1].Data = d.log[n-1].Data[:len(data)]
179-
copy(d.log[n-1].Data, data)
180-
d.log[n-1].Time = time.Since(d.time).Microseconds()
146+
d.log[n].OpCode = opCode
147+
d.log[n].Offset = offset
148+
d.log[n].Length = length
149+
d.log[n].Data = d.log[n].Data[:len(data)]
150+
copy(d.log[n].Data, data)
151+
d.log[n].Time = time.Since(d.time).Microseconds()
181152
d.time = d.time.Add(time.Since(d.time))
182-
d.log[n-1].valid = true
153+
d.log[n].valid = true
183154
}
184155

185156
func (d *RecorderDisk) ClearLog() {
@@ -193,7 +164,7 @@ func (d *RecorderDisk) GetLog() []RecorderRecord {
193164
return d.log
194165
}
195166

196-
func (r RecorderRecord) String() (string, bool) {
167+
func (r *RecorderRecord) String() (string, bool) {
197168
opCode := "Unknown"
198169
switch r.OpCode {
199170
case RecorderOpCodeRead:
@@ -203,5 +174,5 @@ func (r RecorderRecord) String() (string, bool) {
203174
case RecorderOpCodeEraseBlocks:
204175
opCode = "EraseBlocks"
205176
}
206-
return fmt.Sprintf("%s: %05d+%02d t:%d| % 0x", opCode, r.Offset, r.Length, r.Time, r.Data), r.valid
177+
return fmt.Sprintf("%s: %05d+%02d t:%d | % 0x", opCode, r.Offset, r.Length, r.Time, r.Data), r.valid
207178
}

src/machine/usb/msc/msc.go

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ var MSC *msc
2828

2929
type msc struct {
3030
buf []byte // Buffer for incoming/outgoing data
31+
blockCache []byte // Buffer for block read/write data
3132
taskQueued bool // Flag to indicate if the buffer has a task queued
3233
rxStalled bool // Flag to indicate if the RX endpoint is stalled
3334
txStalled bool // Flag to indicate if the TX endpoint is stalled
@@ -42,12 +43,13 @@ type msc struct {
4243
cswBuf []byte // CSW response buffer
4344
state mscState
4445

45-
maxLUN uint8 // Maximum Logical Unit Number (n-1 for n LUNs)
46-
dev machine.BlockDevice
47-
blockCount uint32 // Number of blocks in the device
48-
blockRatio uint32 // Number of real blocks per emulated block
49-
blockSize uint32 // Write block size of the device
50-
readOnly bool
46+
maxLUN uint8 // Maximum Logical Unit Number (n-1 for n LUNs)
47+
dev machine.BlockDevice
48+
blockCount uint32 // Number of blocks in the device
49+
blockOffset uint32 // Byte offset of the first block in the device for aligned writes
50+
blockSizeUSB uint32 // Write block size as presented to the host over USB
51+
blockSizeRaw uint32 // Write block size of the underlying device hardware
52+
readOnly bool
5153

5254
vendorID [8]byte // Max 8 ASCII characters
5355
productID [16]byte // Max 16 ASCII characters
@@ -85,7 +87,10 @@ func newMSC(dev machine.BlockDevice) *msc {
8587
// Size our buffer to match the maximum packet size of the IN endpoint
8688
maxPacketSize := descriptor.EndpointEP8IN.GetMaxPacketSize()
8789
m := &msc{
88-
buf: make([]byte, maxPacketSize),
90+
// Some platforms require reads/writes to be aligned to the full underlying hardware block
91+
blockCache: make([]byte, dev.WriteBlockSize()),
92+
blockSizeUSB: 512,
93+
buf: make([]byte, dev.WriteBlockSize()),
8994
cswBuf: make([]byte, csw.MsgLen),
9095
cbw: &CBW{Data: make([]byte, 31)},
9196
maxPacketSize: uint32(maxPacketSize),
@@ -135,12 +140,13 @@ func (m *msc) processTasks() {
135140
cmd := m.cbw.SCSICmd()
136141
switch cmd.CmdType() {
137142
case scsi.CmdWrite:
138-
m.scsiWrite(m.buf)
143+
m.scsiWrite(cmd, m.buf)
139144
case scsi.CmdUnmap:
140145
m.scsiUnmap(m.buf)
141146
}
142147

143-
// If we were waiting for the task buffer to empty, clear the flag
148+
// Acknowledge the received data from the host
149+
m.queuedBytes = 0
144150
m.taskQueued = false
145151
machine.AckEndpointRxMessage(usb.MSC_ENDPOINT_OUT)
146152
}

src/machine/usb/msc/scsi.go

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ func (m *msc) scsiCmdBegin(b []byte) {
2323

2424
if m.totalBytes > 0 && m.cbw.isOut() {
2525
// Reject any other multi-packet commands
26-
if m.totalBytes > uint32(cap(m.buf)) {
26+
if m.totalBytes > m.maxPacketSize {
2727
m.sendScsiError(csw.StatusFailed, scsi.SenseIllegalRequest, scsi.SenseCodeInvalidCmdOpCode)
2828
return
2929
} else {
@@ -87,7 +87,7 @@ func (m *msc) scsiDataTransfer(b []byte) bool {
8787
m.sendScsiError(csw.StatusFailed, scsi.SenseDataProtect, scsi.SenseCodeWriteProtected)
8888
return true
8989
}
90-
return m.scsiQueueTask(b)
90+
return m.scsiQueueTask(cmdType, b)
9191
}
9292

9393
// Update our sent bytes count to include the just-confirmed bytes
@@ -129,7 +129,7 @@ func (m *msc) scsiCmdReadCapacity(cmd scsi.Cmd) {
129129
// Last LBA address (big endian)
130130
binary.BigEndian.PutUint32(m.buf[:4], m.blockCount-1)
131131
// Block size (big endian)
132-
binary.BigEndian.PutUint32(m.buf[4:8], m.blockSize)
132+
binary.BigEndian.PutUint32(m.buf[4:8], m.blockSizeUSB)
133133
}
134134

135135
func (m *msc) scsiCmdReadFormatCapacity(cmd scsi.Cmd) {
@@ -142,7 +142,7 @@ func (m *msc) scsiCmdReadFormatCapacity(cmd scsi.Cmd) {
142142
// Number of blocks (big endian)
143143
binary.BigEndian.PutUint32(m.buf[4:8], m.blockCount)
144144
// Block size (24-bit, big endian)
145-
binary.BigEndian.PutUint32(m.buf[8:12], m.blockSize)
145+
binary.BigEndian.PutUint32(m.buf[8:12], m.blockSizeUSB)
146146
// Descriptor Type - formatted media
147147
m.buf[8] = 2
148148
}
@@ -210,6 +210,7 @@ func (m *msc) scsiCmdRequestSense() {
210210
// Set the buffer size to the SCSI sense message size and clear
211211
m.resetBuffer(scsi.RequestSenseRespLen)
212212
m.queuedBytes = scsi.RequestSenseRespLen
213+
m.totalBytes = scsi.RequestSenseRespLen
213214

214215
// 0x70 - current error, 0x71 - deferred error (not used)
215216
m.buf[0] = 0xF0 // 0x70 for current error plus 0x80 for valid flag bit
@@ -241,28 +242,39 @@ func (m *msc) scsiCmdUnmap(cmd scsi.Cmd) {
241242
}
242243
}
243244

244-
func (m *msc) scsiQueueTask(b []byte) bool {
245+
func (m *msc) scsiQueueTask(cmdType scsi.CmdType, b []byte) bool {
245246
// Check if the incoming data is larger than our buffer
246-
if len(b) > cap(m.buf) {
247+
if int(m.queuedBytes)+len(b) > cap(m.buf) {
247248
m.sendScsiError(csw.StatusFailed, scsi.SenseIllegalRequest, scsi.SenseCodeInvalidFieldInCDB)
248249
return true
249250
}
250251

251-
// Save the incoming data in our buffer for processing outside of interrupt context
252+
// Save the incoming data in our buffer for processing outside of interrupt context.
252253
if m.taskQueued {
253254
// If we already have a full task queue we can't accept this data
254255
m.sendScsiError(csw.StatusFailed, scsi.SenseAbortedCommand, scsi.SenseCodeMsgReject)
255256
return true
256257
}
257258

258259
// Copy the queued task data into our buffer
259-
m.buf = m.buf[:len(b)]
260-
copy(m.buf, b)
261-
m.queuedBytes = uint32(len(b))
262-
m.taskQueued = true
260+
start := m.queuedBytes
261+
end := start + uint32(len(b))
262+
m.buf = m.buf[:end]
263+
copy(m.buf[start:end], b)
264+
m.queuedBytes += uint32(len(b))
263265

264-
// Don't acknowledge the incoming data until we can process it
265-
return false
266+
switch cmdType {
267+
case scsi.CmdWrite:
268+
// If we're writing data wait until we have a full write block of data that can be processed.
269+
if m.queuedBytes == uint32(cap(m.blockCache)) {
270+
m.taskQueued = true
271+
}
272+
case scsi.CmdUnmap:
273+
m.taskQueued = true
274+
}
275+
276+
// Don't acknowledge the incoming data until we can process it.
277+
return !m.taskQueued
266278
}
267279

268280
func (m *msc) sendScsiError(status csw.Status, key scsi.Sense, code scsi.SenseCode) {

0 commit comments

Comments
 (0)