Skip to content
Merged
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
21 changes: 11 additions & 10 deletions src/machine/usb/msc/msc.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ type msc struct {
respStatus csw.Status // Response status for the last command
sendZLP bool // Flag to indicate if a zero-length packet should be sent before sending CSW

cbw *CBW // Last received Command Block Wrapper
queuedBytes uint32 // Number of bytes queued for sending
sentBytes uint32 // Number of bytes sent
totalBytes uint32 // Total bytes to send
cswBuf []byte // CSW response buffer
state mscState
cbw *CBW // Last received Command Block Wrapper
queuedBytes uint32 // Number of bytes queued for sending
sentBytes uint32 // Number of bytes sent
transferBytes uint32 // Total bytes to send
cswBuf []byte // CSW response buffer
state mscState

maxLUN uint8 // Maximum Logical Unit Number (n-1 for n LUNs)
dev machine.BlockDevice
Expand Down Expand Up @@ -160,8 +160,9 @@ func (m *msc) sendUSBPacket(b []byte) {
func (m *msc) sendCSW(status csw.Status) {
// Generate CSW packet into m.cswBuf and send it
residue := uint32(0)
if m.totalBytes >= m.sentBytes {
residue = m.totalBytes - m.sentBytes
expected := m.cbw.transferLength()
if expected >= m.sentBytes {
residue = expected - m.sentBytes
}
m.cbw.CSW(status, residue, m.cswBuf)
m.state = mscStateStatusSent
Expand Down Expand Up @@ -245,7 +246,7 @@ func (m *msc) run(b []byte, isEpOut bool) bool {

// Move on to the data transfer phase next go around (after sending the first message)
m.state = mscStateData
m.totalBytes = cbw.transferLength()
m.transferBytes = cbw.transferLength()
m.queuedBytes = 0
m.sentBytes = 0
m.respStatus = csw.StatusPassed
Expand Down Expand Up @@ -281,7 +282,7 @@ func (m *msc) run(b []byte, isEpOut bool) bool {
// to cycle back through this block, e.g. with TEST UNIT READY which sends only a CSW after
// setting the sense key/add'l code/qualifier internally
if m.state == mscStateStatus && !m.txStalled {
if m.totalBytes > m.sentBytes && m.cbw.isIn() {
if m.cbw.transferLength() > m.sentBytes && m.cbw.isIn() {
// 6.7.2 The Thirteen Cases - Case 5 (Hi > Di): STALL before status
m.stallEndpoint(usb.MSC_ENDPOINT_IN)
} else if m.sendZLP {
Expand Down
27 changes: 16 additions & 11 deletions src/machine/usb/msc/scsi.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ func (m *msc) scsiCmdBegin() {
return
}

if m.totalBytes > 0 && m.cbw.isOut() {
if m.transferBytes > 0 && m.cbw.isOut() {
// Reject any other multi-packet commands
if m.totalBytes > m.maxPacketSize {
if m.transferBytes > m.maxPacketSize {
m.sendScsiError(csw.StatusFailed, scsi.SenseIllegalRequest, scsi.SenseCodeInvalidCmdOpCode)
return
} else {
Expand Down Expand Up @@ -53,7 +53,7 @@ func (m *msc) scsiCmdBegin() {
}

if len(m.buf) == 0 {
if m.totalBytes > 0 {
if m.transferBytes > 0 {
// 6.7.2 The Thirteen Cases - Case 4 (Hi > Dn)
// https://usb.org/sites/default/files/usbmassbulk_10.pdf
m.sendScsiError(csw.StatusFailed, scsi.SenseIllegalRequest, 0)
Expand All @@ -63,7 +63,7 @@ func (m *msc) scsiCmdBegin() {
m.state = mscStateStatus
}
} else {
if m.totalBytes == 0 {
if m.transferBytes == 0 {
// 6.7.1 The Thirteen Cases - Case 2 (Hn < Di)
// https://usb.org/sites/default/files/usbmassbulk_10.pdf
m.sendScsiError(csw.StatusFailed, scsi.SenseIllegalRequest, 0)
Expand All @@ -72,6 +72,7 @@ func (m *msc) scsiCmdBegin() {
if m.cbw.transferLength() < uint32(len(m.buf)) {
m.buf = m.buf[:m.cbw.transferLength()]
}
m.queuedBytes = uint32(len(m.buf))
m.sendUSBPacket(m.buf)
}
}
Expand All @@ -93,7 +94,7 @@ func (m *msc) scsiDataTransfer(b []byte) bool {
// Update our sent bytes count to include the just-confirmed bytes
m.sentBytes += m.queuedBytes

if m.sentBytes >= m.totalBytes {
if m.sentBytes >= m.transferBytes {
// Transfer complete, send CSW after transfer confirmed
m.state = mscStateStatus
} else if cmdType == scsi.CmdRead {
Expand Down Expand Up @@ -158,8 +159,8 @@ func (m *msc) scsiCmdModeSense(cmd scsi.Cmd) {

// The host allows a good amount of leeway in response size
// Reset total bytes to what we'll actually send
if m.totalBytes > respLen {
m.totalBytes = respLen
if m.transferBytes > respLen {
m.transferBytes = respLen
m.sendZLP = true
}

Expand Down Expand Up @@ -210,7 +211,7 @@ func (m *msc) scsiCmdRequestSense() {
// Set the buffer size to the SCSI sense message size and clear
m.resetBuffer(scsi.RequestSenseRespLen)
m.queuedBytes = scsi.RequestSenseRespLen
m.totalBytes = scsi.RequestSenseRespLen
m.transferBytes = scsi.RequestSenseRespLen

// 0x70 - current error, 0x71 - deferred error (not used)
m.buf[0] = 0xF0 // 0x70 for current error plus 0x80 for valid flag bit
Expand Down Expand Up @@ -266,7 +267,7 @@ func (m *msc) scsiQueueTask(cmdType scsi.CmdType, b []byte) bool {
switch cmdType {
case scsi.CmdWrite:
// If we're writing data wait until we have a full write block of data that can be processed.
if m.queuedBytes == uint32(cap(m.blockCache)) {
if m.queuedBytes == uint32(cap(m.blockCache)) || (m.sentBytes+m.queuedBytes >= m.transferBytes) {
m.taskQueued = true
}
case scsi.CmdUnmap:
Expand All @@ -279,7 +280,11 @@ func (m *msc) scsiQueueTask(cmdType scsi.CmdType, b []byte) bool {

func (m *msc) sendScsiError(status csw.Status, key scsi.Sense, code scsi.SenseCode) {
// Generate CSW into m.cswBuf
residue := m.totalBytes - m.sentBytes
expected := m.cbw.transferLength()
residue := uint32(0)
if expected > m.sentBytes {
residue = expected - m.sentBytes
}

// Prepare to send CSW
m.sendZLP = true // Ensure the transaction is signaled as ended before a CSW is sent
Expand All @@ -291,7 +296,7 @@ func (m *msc) sendScsiError(status csw.Status, key scsi.Sense, code scsi.SenseCo
m.addlSenseCode = code
m.addlSenseQualifier = 0x00 // Not used

if m.totalBytes > 0 && residue > 0 {
if expected > 0 && residue > 0 {
if m.cbw.isIn() {
m.stallEndpoint(usb.MSC_ENDPOINT_IN)
} else {
Expand Down
4 changes: 2 additions & 2 deletions src/machine/usb/msc/scsi_inquiry.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,13 +136,13 @@ func (m *msc) scsiEvpdInquiry(cmd scsi.Cmd, pageCode uint8) {

// Set total bytes to the length of our response
m.queuedBytes = uint32(len(m.buf))
m.totalBytes = uint32(len(m.buf))
m.transferBytes = uint32(len(m.buf))
}

func (m *msc) scsiStdInquiry(cmd scsi.Cmd) {
m.resetBuffer(scsi.InquiryRespLen)
m.queuedBytes = scsi.InquiryRespLen
m.totalBytes = scsi.InquiryRespLen
m.transferBytes = scsi.InquiryRespLen

// byte 0 - Device Type (0x00 for direct access block device)
// byte 1 - Removable media bit
Expand Down
10 changes: 5 additions & 5 deletions src/machine/usb/msc/scsi_readwrite.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ func (m *msc) scsiCmdReadWrite(cmd scsi.Cmd) {
status := m.validateScsiReadWrite(cmd)
if status != csw.StatusPassed {
m.sendScsiError(status, scsi.SenseIllegalRequest, scsi.SenseCodeInvalidCmdOpCode)
} else if m.totalBytes > 0 {
} else if m.transferBytes > 0 {
if cmd.CmdType() == scsi.CmdRead {
m.scsiRead(cmd)
} else {
Expand All @@ -28,7 +28,7 @@ func (m *msc) scsiCmdReadWrite(cmd scsi.Cmd) {
func (m *msc) validateScsiReadWrite(cmd scsi.Cmd) csw.Status {
blockCount := cmd.BlockCount()
// CBW wrapper transfer length
if m.totalBytes == 0 {
if m.transferBytes == 0 {
// If the SCSI command's block count doesn't loosely match the wrapper's transfer length something's wrong
if blockCount > 0 {
return csw.StatusPhaseError
Expand All @@ -50,7 +50,7 @@ func (m *msc) validateScsiReadWrite(cmd scsi.Cmd) csw.Status {
// https://usb.org/sites/default/files/usbmassbulk_10.pdf
return csw.StatusFailed
}
if m.totalBytes/blockCount == 0 {
if m.transferBytes/blockCount == 0 {
// Block size shouldn't be small enough to round to zero
// 6.7.2 The Thirteen Cases - Case 7 (Hi < Di) READ(10) or
// 6.7.3 The Thirteen Cases - Case 13 (Ho < Do) WRITE(10)
Expand Down Expand Up @@ -103,7 +103,7 @@ func (m *msc) writeBlock(b []byte, lba, offset uint32) (n int, err error) {

func (m *msc) scsiRead(cmd scsi.Cmd) {
// Make sure we don't exceed the buffer size
readEnd := m.totalBytes - m.sentBytes
readEnd := m.transferBytes - m.sentBytes
if readEnd > m.maxPacketSize {
readEnd = m.maxPacketSize
}
Expand Down Expand Up @@ -136,7 +136,7 @@ func (m *msc) scsiWrite(cmd scsi.Cmd, b []byte) {
m.sentBytes += uint32(len(b))
}

if m.sentBytes >= m.totalBytes {
if m.sentBytes >= m.transferBytes {
// Data transfer is complete, send CSW
m.state = mscStateStatus
m.run([]byte{}, true)
Expand Down
2 changes: 1 addition & 1 deletion src/machine/usb/msc/scsi_unmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func (m *msc) scsiUnmap(b []byte) {
// FIXME: We need to handle erase block alignment

m.sentBytes += uint32(len(b))
if m.sentBytes >= m.totalBytes {
if m.sentBytes >= m.transferBytes {
// Order 66 complete, send CSW to establish galactic empire
m.state = mscStateStatus
m.run([]byte{}, true)
Expand Down
24 changes: 15 additions & 9 deletions src/machine/usb/msc/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package msc
import (
"machine"
"machine/usb"
"machine/usb/msc/csw"
)

func setupPacketHandler(setup usb.Setup) bool {
Expand All @@ -18,11 +17,17 @@ func (m *msc) setupPacketHandler(setup usb.Setup) bool {
wValue := (uint16(setup.WValueH) << 8) | uint16(setup.WValueL)
switch setup.BRequest {
case usb.CLEAR_FEATURE:
ok = m.handleClearFeature(setup, wValue)
if setup.BmRequestType == 0x02 { // Host-to-Device | Standard | Endpoint
ok = m.handleClearFeature(setup, wValue)
}
case usb.GET_MAX_LUN:
ok = m.handleGetMaxLun(setup, wValue)
if setup.BmRequestType == 0xA1 { // Device-to-Host | Class | Interface
ok = m.handleGetMaxLun(setup, wValue)
}
case usb.MSC_RESET:
ok = m.handleReset(setup, wValue)
if setup.BmRequestType == 0x21 { // Host-to-Device | Class | Interface
ok = m.handleReset(setup, wValue)
}
}
return ok
}
Expand Down Expand Up @@ -53,24 +58,25 @@ func (m *msc) handleClearFeature(setup usb.Setup, wValue uint16) bool {
} else if wIndex == usb.MSC_ENDPOINT_OUT {
m.stallEndpoint(usb.MSC_ENDPOINT_OUT)
}
return ok
machine.SendZlp()
return true
}

// Clear the direction bit from the endpoint address for comparison
wIndex := setup.WIndex & 0x7F

// Clear the IN/OUT stalls if addressed to the endpoint, or both if addressed to the interface
if wIndex == usb.MSC_ENDPOINT_IN || wIndex == mscInterface {
// Clear the IN/OUT stalls if addressed to the endpoint
if wIndex == usb.MSC_ENDPOINT_IN {
m.clearStallEndpoint(usb.MSC_ENDPOINT_IN)
ok = true
}
if wIndex == usb.MSC_ENDPOINT_OUT || wIndex == mscInterface {
if wIndex == usb.MSC_ENDPOINT_OUT {
m.clearStallEndpoint(usb.MSC_ENDPOINT_OUT)
ok = true
}
// Send a CSW if needed to resume after the IN endpoint stall is cleared
if m.state == mscStateStatus && wIndex == usb.MSC_ENDPOINT_IN {
m.sendCSW(csw.StatusPassed)
m.sendCSW(m.respStatus)
ok = true
}

Expand Down
Loading