working BlockDevice

This commit is contained in:
soypat
2024-01-16 00:46:50 -03:00
parent 0d80962dc8
commit 964364005d
3 changed files with 178 additions and 97 deletions
+60 -9
View File
@@ -48,14 +48,65 @@ func main() {
cid := sdcard.CID()
fmt.Printf("name=%s\ncsd=\n%s\n", cid.ProductName(), csd.String())
var buf [512]byte
for i := 0; i < 11; i += 1 {
err = sdcard.ReadBlocks(buf[:], int64(i))
if err != nil {
println("err reading block", i, ":", err.Error())
continue
}
expectCRC := sd.CRC16(buf[:])
fmt.Printf("block %d theircrc=%#x ourcrc=%#x:\n\t%#x\n", i, sdcard.LastReadCRC(), expectCRC, buf[:])
const placeholderEraseSectorSize = 512
bd, err := sd.NewBlockDevice(sdcard, int(csd.ReadBlockLen()), csd.NumberOfBlocks(), placeholderEraseSectorSize)
if err != nil {
panic("block device creation:" + err.Error())
}
var mc MemChecker
ok, badBlkIdx, err := mc.MemCheck(bd, 2, 100)
if err != nil {
panic("memcheck:" + err.Error())
}
if !ok {
println("bad block", badBlkIdx)
} else {
println("memcheck ok")
}
}
type MemChecker struct {
rdBuf []byte
storeBuf []byte
wrBuf []byte
}
func (mc *MemChecker) MemCheck(bd *sd.BlockDevice, blockIdx, numBlocks int64) (memOK bool, badBlockIdx int64, err error) {
size := bd.BlockSize() * numBlocks
if len(mc.rdBuf) < int(size) {
mc.rdBuf = make([]byte, size)
mc.wrBuf = make([]byte, size)
mc.storeBuf = make([]byte, size)
for i := range mc.wrBuf {
mc.wrBuf[i] = byte(i)
}
}
// Start by storing the original block contents.
_, err = bd.ReadAt(mc.storeBuf, blockIdx)
if err != nil {
return false, blockIdx, err
}
// Write the test pattern.
_, err = bd.WriteAt(mc.wrBuf, blockIdx)
if err != nil {
return false, blockIdx, err
}
// Read back the test pattern.
_, err = bd.ReadAt(mc.rdBuf, blockIdx)
if err != nil {
return false, blockIdx, err
}
for j := 0; j < len(mc.rdBuf); j++ {
// Compare the read back data with the test pattern.
if mc.rdBuf[j] != mc.wrBuf[j] {
badBlock := blockIdx + int64(j)/bd.BlockSize()
return false, badBlock, nil
}
mc.rdBuf[j] = 0
}
// Leave the card in it's previous state.
_, err = bd.WriteAt(mc.storeBuf, blockIdx)
return true, -1, nil
}
+44 -30
View File
@@ -18,10 +18,10 @@ var _ io.WriterAt = (*BlockDevice)(nil)
type Card interface {
// WriteBlocks writes the given data to the card, starting at the given block index.
// The data must be a multiple of the block size.
WriteBlocks(data []byte, startBlockIdx int64) error
WriteBlocks(data []byte, startBlockIdx int64) (int, error)
// ReadBlocks reads the given number of blocks from the card, starting at the given block index.
// The dst buffer must be a multiple of the block size.
ReadBlocks(dst []byte, startBlockIdx int64) error
ReadBlocks(dst []byte, startBlockIdx int64) (int, error)
// EraseSectors erases sectors starting at startSectorIdx to startSectorIdx+numSectors.
EraseSectors(startSectorIdx, numSectors int64) error
}
@@ -59,13 +59,12 @@ func (bd *BlockDevice) ReadAt(p []byte, off int64) (n int, err error) {
if off < 0 {
return 0, errNegativeOffset
}
blockSize := len(bd.blockbuf)
blockIdx := bd.blk.idx(off)
blockOff := bd.blk.off(off)
if blockOff != 0 {
// Non-aligned first block case.
println("read", len(bd.blockbuf), "bytes from block", blockIdx)
if err := bd.card.ReadBlocks(bd.blockbuf, blockIdx); err != nil {
if _, err = bd.card.ReadBlocks(bd.blockbuf, blockIdx); err != nil {
return n, err
}
n += copy(p, bd.blockbuf[blockOff:])
@@ -73,22 +72,22 @@ func (bd *BlockDevice) ReadAt(p []byte, off int64) (n int, err error) {
blockIdx++
}
remaining := len(p) - n
if remaining >= blockSize {
fullBlocksToRead := bd.blk.idx(int64(len(p)))
if fullBlocksToRead > 0 {
// 1 or more full blocks case.
endOffset := remaining - int(bd.blk.off(int64(remaining)))
err = bd.card.ReadBlocks(p[:endOffset], blockIdx)
endOffset := fullBlocksToRead * bd.blk.size()
ngot, err := bd.card.ReadBlocks(p[:endOffset], blockIdx)
if err != nil {
return n, err
return n + ngot, err
}
p = p[endOffset:]
n += endOffset
blockIdx += int64(endOffset / blockSize)
n += ngot
blockIdx += fullBlocksToRead
}
if len(p) > 0 {
// Non-aligned last block case.
if err := bd.card.ReadBlocks(bd.blockbuf, blockIdx); err != nil {
if _, err := bd.card.ReadBlocks(bd.blockbuf, blockIdx); err != nil {
return n, err
}
n += copy(p, bd.blockbuf)
@@ -101,51 +100,66 @@ func (bd *BlockDevice) WriteAt(p []byte, off int64) (n int, err error) {
if off < 0 {
return 0, errNegativeOffset
}
blockSize := len(bd.blockbuf)
blockIdx := bd.blk.idx(off)
blockOff := bd.blk.off(off)
if blockOff != 0 {
// Non-aligned first block case.
if err := bd.card.ReadBlocks(bd.blockbuf, blockIdx); err != nil {
if _, err := bd.card.ReadBlocks(bd.blockbuf, blockIdx); err != nil {
return n, err
}
n += copy(bd.blockbuf[blockOff:], p)
if err := bd.card.WriteBlocks(bd.blockbuf, blockIdx); err != nil {
nexpect := copy(bd.blockbuf[blockOff:], p)
ngot, err := bd.card.WriteBlocks(bd.blockbuf, blockIdx)
if err != nil {
return n, err
} else if ngot != len(bd.blockbuf) {
return n, io.ErrShortWrite
}
p = p[n:]
n += nexpect
p = p[nexpect:]
blockIdx++
}
remaining := len(p) - n
if remaining >= blockSize {
fullBlocksToWrite := bd.blk.idx(int64(len(p)))
if fullBlocksToWrite > 0 {
// 1 or more full blocks case.
endOffset := remaining - int(bd.blk.off(int64(remaining)))
err = bd.card.WriteBlocks(p[:endOffset], blockIdx)
endOffset := fullBlocksToWrite * bd.blk.size()
ngot, err := bd.card.WriteBlocks(p[:endOffset], blockIdx)
n += ngot
if err != nil {
return n, err
} else if ngot != int(endOffset) {
return n, io.ErrShortWrite
}
p = p[endOffset:]
n += endOffset
blockIdx += int64(endOffset / blockSize)
p = p[ngot:]
blockIdx += fullBlocksToWrite
}
if len(p) > 0 {
// Non-aligned last block case.
if err := bd.card.ReadBlocks(bd.blockbuf, blockIdx); err != nil {
if _, err := bd.card.ReadBlocks(bd.blockbuf, blockIdx); err != nil {
return n, err
}
n += copy(bd.blockbuf, p)
if err := bd.card.WriteBlocks(bd.blockbuf, blockIdx); err != nil {
copy(bd.blockbuf, p)
ngot, err := bd.card.WriteBlocks(bd.blockbuf, blockIdx)
if err != nil {
return n, err
} else if ngot != len(bd.blockbuf) {
return n, io.ErrShortWrite
}
n += len(p)
}
return n, nil
}
// Size returns the number of bytes in this block device.
func (bd *BlockDevice) Size() int64 {
return int64(len(bd.blockbuf)) * bd.numblocks
return bd.BlockSize() * bd.numblocks
}
// BlockSize returns the size of a block in bytes.
func (bd *BlockDevice) BlockSize() int64 {
return bd.blk.size()
}
// EraseBlocks erases the given number of blocks. An implementation may
@@ -163,7 +177,7 @@ func (bd *BlockDevice) EraseBlockSize() int64 {
return bd.eraseBlockSize
}
// blkIdxer is a helper for calculating block indexes and offsets.
// blkIdxer is a helper for calculating block indices and offsets.
type blkIdxer struct {
blockshift int64
blockmask int64
+74 -58
View File
@@ -143,121 +143,136 @@ func (d *SPICard) updateCSDCID() (err error) {
}
// ReadBlock reads to a buffer multiple of 512 bytes from sdcard into dst starting at block `startBlockIdx`.
func (d *SPICard) ReadBlocks(dst []byte, startBlockIdx int64) error {
func (d *SPICard) ReadBlocks(dst []byte, startBlockIdx int64) (int, error) {
numblocks, err := d.checkBounds(startBlockIdx, len(dst))
if err != nil {
return err
return 0, err
}
if d.kind != TypeSDHC {
startBlockIdx <<= 9 // Multiply by 512 for non high capacity SD cards.
}
d.csEnable(true)
defer d.endTx()
defer d.csEnable(false)
if numblocks == 1 {
_, err := d.card_command(cmdReadSingleBlock, uint32(startBlockIdx))
if err != nil {
return err
}
return d.read_data(dst)
return d.read_block_single(dst, startBlockIdx)
} else if numblocks > 1 {
// TODO: implement multi block transaction reading.
// Rust code is failing here.
blocksize := int(d.blk.size())
_, err = d.card_command(cmdReadMultipleBlock, uint32(startBlockIdx))
if err != nil {
return err
}
for i := 0; i < numblocks; i++ {
offset := i * blocksize
err = d.read_data(dst[offset : offset+blocksize])
dataoff := i * blocksize
d.csEnable(true)
_, err := d.read_block_single(dst[dataoff:dataoff+blocksize], int64(i)+startBlockIdx)
if err != nil {
return err
return dataoff, err
}
d.csEnable(false)
}
return nil
return len(dst), nil
}
panic("unreachable numblocks<=0")
}
func (d *SPICard) endTx() {
d.card_command(cmdStopTransmission, 0)
d.csEnable(false)
}
func (d *SPICard) EraseSectors(startSector, numberSectors int64) error {
return errors.New("sd:erase not implemented")
}
// WriteBlocks writes to sdcard from a buffer multiple of 512 bytes from src starting at block `startBlockIdx`.
func (d *SPICard) WriteBlocks(data []byte, startBlockIdx int64) error {
func (d *SPICard) WriteBlocks(data []byte, startBlockIdx int64) (int, error) {
numblocks, err := d.checkBounds(startBlockIdx, len(data))
if err != nil {
return err
return 0, err
}
if d.kind != TypeSDHC {
startBlockIdx <<= 9 // Multiply by 512 for non high capacity SD cards.
}
d.csEnable(true)
defer d.endTx()
defer d.csEnable(false)
writeTimeout := 2 * d.timeout
if numblocks == 1 {
_, err = d.card_command(cmdWriteBlock, uint32(startBlockIdx))
if err != nil {
return err
}
err = d.write_data(tokSTART_BLOCK, data)
if err != nil {
return err
}
err = d.wait_not_busy(writeTimeout)
if err != nil {
return err
}
status, err := d.card_command(cmdSendStatus, 0)
if err != nil {
return err
} else if status != 0 {
return makeResponseError(response1(status))
}
status, err = d.receive()
if err != nil {
return err
} else if status != 0 {
return errWrite
}
return nil
return d.write_block_single(data, startBlockIdx)
} else if numblocks > 1 {
// Start multi block write.
blocksize := 1 << d.blk.size()
blocksize := int(d.blk.size())
_, err = d.card_command(cmdWriteMultipleBlock, uint32(startBlockIdx))
if err != nil {
return err
return 0, err
}
for i := 0; i < numblocks; i++ {
offset := i * blocksize
err = d.wait_not_busy(writeTimeout)
if err != nil {
return err
return 0, err
}
err = d.write_data(tokWRITE_MULT, data[offset:offset+blocksize])
if err != nil {
return err
return 0, err
}
}
// Stop the multi write operation.
err = d.wait_not_busy(writeTimeout)
if err != nil {
return err
return 0, err
}
return d.send(tokSTOP_TRAN)
err = d.send(tokSTOP_TRAN)
if err != nil {
return 0, err
}
_, err = d.card_command(cmdStopTransmission, 0)
if err != nil {
return 0, err
}
return len(data), nil
}
panic("unreachable numblocks<=0")
}
func (d *SPICard) read_block_single(dst []byte, startBlockIdx int64) (int, error) {
_, err := d.card_command(cmdReadSingleBlock, uint32(startBlockIdx))
if err != nil {
return 0, err
}
err = d.read_data(dst)
if err != nil {
return 0, err
}
return len(dst), nil
}
func (d *SPICard) write_block_single(data []byte, startBlockIdx int64) (_ int, err error) {
_, err = d.card_command(cmdWriteBlock, uint32(startBlockIdx))
if err != nil {
return 0, err
}
err = d.write_data(tokSTART_BLOCK, data)
if err != nil {
return 0, err
}
err = d.wait_not_busy(2 * d.timeout)
if err != nil {
return 0, err
}
status, err := d.card_command(cmdSendStatus, 0)
if err != nil {
return 0, err
} else if status != 0 {
return 0, makeResponseError(response1(status))
}
status, err = d.receive()
if err != nil {
return 0, err
} else if status != 0 {
return 0, errWrite
}
return len(data), nil
}
func (d *SPICard) checkBounds(startBlockIdx int64, datalen int) (numblocks int, err error) {
if startBlockIdx >= d.NumberOfBlocks() {
return 0, errOOB
@@ -354,9 +369,10 @@ func (d *SPICard) read_data(data []byte) (err error) {
status, err = d.receive()
if err != nil {
return err
}
if status != 0xff {
} else if status != 0xff {
break
} else if tm.expired() {
return errReadTimeout
}
d.yield()
}