This commit is contained in:
Lei Xue
2017-07-31 21:47:38 +08:00
parent 957564305a
commit 4ae643e9f8
12 changed files with 258 additions and 221 deletions

View File

@@ -16,7 +16,6 @@ limitations under the License.
package api
import (
"bytes"
"errors"
"sync"
@@ -144,8 +143,13 @@ const (
SCSIDataBidirection
)
type SenseBuffer struct {
Buffer []byte
Length uint32
}
type SCSIDataBuffer struct {
Buffer *bytes.Buffer
Buffer []byte
Length uint32
TransferLength uint32
Resid uint32
@@ -166,21 +170,20 @@ type SCSICommand struct {
Device *SCSILu
State SCSICommandState
Direction SCSIDataDirection
InSDBBuffer SCSIDataBuffer
OutSDBBuffer SCSIDataBuffer
InSDBBuffer *SCSIDataBuffer
OutSDBBuffer *SCSIDataBuffer
RelTargetPortID uint16
// Command ITN ID
ITNexusID uuid.UUID
Offset uint64
TL uint32
SCB *bytes.Buffer
SCB []byte
SCBLength int
Lun [8]uint8
Attribute int
Tag uint64
Result byte
SenseBuffer *bytes.Buffer
SenseLength uint32
SenseBuffer *SenseBuffer
ITNexus *ITNexus
ITNexusLuInfo *ITNexusLuInfo
}

View File

@@ -334,7 +334,7 @@ func (m *ISCSICommand) dataInBytes() []byte {
if m.Resid > 0 {
if m.Resid > m.ExpectedDataLen {
flag |= 0x04
} else {
} else if m.Resid < m.ExpectedDataLen {
flag |= 0x02
}
}

View File

@@ -24,6 +24,7 @@ import (
"github.com/gostor/gotgt/pkg/api"
"github.com/gostor/gotgt/pkg/util"
"github.com/gostor/gotgt/pkg/util/pool"
)
const (
@@ -126,7 +127,7 @@ func (c *iscsiConnection) init() {
}
func (c *iscsiConnection) readData(size int) ([]byte, int, error) {
var buf = make([]byte, size)
var buf = pool.NewBuffer(size)
length, err := io.ReadFull(c.conn, buf)
if err != nil {
return nil, -1, err
@@ -179,13 +180,16 @@ func (conn *iscsiConnection) buildRespPackage(oc OpCode, task *iscsiTask) error
scmd := task.scmd
resp.Status = scmd.Result
if scmd.Result != 0 && scmd.SenseBuffer != nil {
length := util.MarshalUint32(uint32(scmd.SenseLength))
resp.RawData = append(length[2:4], scmd.SenseBuffer.Bytes()...)
length := util.MarshalUint32(scmd.SenseBuffer.Length)
resp.RawData = append(length[2:4], scmd.SenseBuffer.Buffer...)
} else if scmd.Direction == api.SCSIDataRead || scmd.Direction == api.SCSIDataWrite {
if scmd.InSDBBuffer.Buffer != nil {
if scmd.InSDBBuffer != nil {
resp.Resid = scmd.InSDBBuffer.Resid
buf := scmd.InSDBBuffer.Buffer.Bytes()
resp.RawData = buf
if resp.Resid != 0 && resp.Resid < scmd.InSDBBuffer.Length {
resp.RawData = scmd.InSDBBuffer.Buffer[:resp.Resid]
} else {
resp.RawData = scmd.InSDBBuffer.Buffer
}
} else {
resp.RawData = []byte{}
}

View File

@@ -17,7 +17,6 @@ limitations under the License.
package iscsit
import (
"bytes"
"fmt"
"net"
"os"
@@ -29,6 +28,7 @@ import (
"github.com/gostor/gotgt/pkg/config"
"github.com/gostor/gotgt/pkg/scsi"
"github.com/gostor/gotgt/pkg/util"
"github.com/gostor/gotgt/pkg/util/pool"
)
const (
@@ -203,6 +203,9 @@ func (s *ISCSITargetDriver) rxHandler(conn *iscsiConnection) {
ddigest uint = 0
final bool = false
cmd *ISCSICommand
buf []byte = make([]byte, BHS_SIZE)
length int
err error
)
conn.readLock.Lock()
defer conn.readLock.Unlock()
@@ -214,7 +217,7 @@ func (s *ISCSITargetDriver) rxHandler(conn *iscsiConnection) {
switch conn.rxIOState {
case IOSTATE_RX_BHS:
log.Debug("rx handler: IOSTATE_RX_BHS")
buf, length, err := conn.readData(BHS_SIZE)
buf, length, err = conn.readData(BHS_SIZE)
if err != nil {
log.Error(err)
return
@@ -224,7 +227,7 @@ func (s *ISCSITargetDriver) rxHandler(conn *iscsiConnection) {
conn.state = CONN_STATE_CLOSE
return
}
conn.rxBuffer = buf
//conn.rxBuffer = buf
cmd, err = parseHeader(buf)
if err != nil {
log.Error(err)
@@ -237,8 +240,10 @@ func (s *ISCSITargetDriver) rxHandler(conn *iscsiConnection) {
conn.rxIOState = IOSTATE_RX_INIT_AHS
break
}
log.Debugf("got command: \n%s", cmd.String())
log.Debugf("got buffer: %v", buf)
if log.GetLevel() == log.DebugLevel {
log.Debugf("got command: \n%s", cmd.String())
log.Debugf("got buffer: %v", buf)
}
final = true
case IOSTATE_RX_INIT_AHS:
conn.rxIOState = IOSTATE_RX_DATA
@@ -254,7 +259,7 @@ func (s *ISCSITargetDriver) rxHandler(conn *iscsiConnection) {
return
}
dl := ((cmd.DataLen + DataPadding - 1) / DataPadding) * DataPadding
buf := []byte{}
cmd.RawData = pool.NewBuffer(dl)
length := 0
for length < dl {
b, l, err := conn.readData(dl - length)
@@ -262,8 +267,8 @@ func (s *ISCSITargetDriver) rxHandler(conn *iscsiConnection) {
log.Error(err)
return
}
copy(cmd.RawData[length:], b)
length += l
buf = append(buf, b...)
}
if length != dl {
log.Debugf("get length is %d, but expected %d", length, dl)
@@ -271,10 +276,7 @@ func (s *ISCSITargetDriver) rxHandler(conn *iscsiConnection) {
conn.state = CONN_STATE_CLOSE
return
}
cmd.RawData = buf[:length]
conn.rxBuffer = append(conn.rxBuffer, buf...)
final = true
log.Debugf("got command: \n%s", cmd.String())
default:
log.Errorf("error %d %d\n", conn.state, conn.rxIOState)
return
@@ -547,21 +549,48 @@ func (s *ISCSITargetDriver) scsiCommandHandler(conn *iscsiConnection) (err error
switch req.OpCode {
case OpSCSICmd:
log.Debugf("SCSI Command processing...")
scmd := &api.SCSICommand{}
scmd := &api.SCSICommand{
ITNexusID: conn.session.ITNexus.ID,
SCB: req.CDB,
SCBLength: len(req.CDB),
Lun: req.LUN,
Tag: uint64(req.TaskTag),
RelTargetPortID: conn.session.TPGT,
}
if req.Read {
if req.Write {
scmd.Direction = api.SCSIDataBidirection
} else {
scmd.Direction = api.SCSIDataRead
}
} else {
if req.Write {
scmd.Direction = api.SCSIDataWrite
}
}
task := &iscsiTask{conn: conn, cmd: conn.req, tag: conn.req.TaskTag, scmd: scmd}
if req.Write {
task.offset = req.DataLen
task.r2tCount = int(req.ExpectedDataLen) - req.DataLen
if !req.Final {
task.unsolCount = 1
}
// new buffer for the data out
if scmd.OutSDBBuffer == nil {
blen := int(req.ExpectedDataLen)
if blen == 0 {
blen = int(req.DataLen)
}
scmd.OutSDBBuffer = &api.SCSIDataBuffer{
Length: uint32(blen),
Buffer: pool.NewBuffer(blen),
}
}
log.Debugf("SCSI write, R2T count: %d, unsol Count: %d, offset: %d", task.r2tCount, task.unsolCount, task.offset)
if task.scmd.OutSDBBuffer.Buffer == nil {
task.scmd.OutSDBBuffer.Buffer = bytes.NewBuffer([]byte{})
}
if conn.session.SessionParam[ISCSI_PARAM_IMM_DATA_EN].Value == 1 {
task.scmd.OutSDBBuffer.Buffer.Write(conn.req.RawData)
copy(scmd.OutSDBBuffer.Buffer[task.offset:], conn.req.RawData)
task.offset += conn.req.DataLen
}
if task.r2tCount > 0 {
// prepare to receive more data
@@ -579,6 +608,11 @@ func (s *ISCSITargetDriver) scsiCommandHandler(conn *iscsiConnection) (err error
return nil
}
}
} else if scmd.InSDBBuffer == nil {
scmd.InSDBBuffer = &api.SCSIDataBuffer{
Length: uint32(req.ExpectedDataLen),
Buffer: pool.NewBuffer(int(req.ExpectedDataLen)),
}
}
task.offset = 0
conn.rxTask = task
@@ -616,9 +650,9 @@ func (s *ISCSITargetDriver) scsiCommandHandler(conn *iscsiConnection) (err error
log.Error(err)
return
}
task.offset = task.offset + conn.req.DataLen
copy(task.scmd.OutSDBBuffer.Buffer[task.offset:], conn.req.RawData)
task.offset += conn.req.DataLen
task.r2tCount = task.r2tCount - conn.req.DataLen
task.scmd.OutSDBBuffer.Buffer.Write(conn.req.RawData)
log.Debugf("Final: %v", conn.req.Final)
log.Debugf("r2tCount: %v", task.r2tCount)
if !conn.req.Final {
@@ -722,27 +756,7 @@ func (s *ISCSITargetDriver) iscsiExecTask(task *iscsiTask) error {
cmd := task.cmd
switch cmd.OpCode {
case OpSCSICmd, OpSCSIOut:
if cmd.Read {
if cmd.Write {
task.scmd.Direction = api.SCSIDataBidirection
} else {
task.scmd.Direction = api.SCSIDataRead
}
} else {
if cmd.Write {
task.scmd.Direction = api.SCSIDataWrite
}
}
task.scmd.ITNexusID = task.conn.session.ITNexus.ID
task.scmd.SCB = bytes.NewBuffer(cmd.CDB)
task.scmd.SCBLength = len(cmd.CDB)
task.scmd.Lun = cmd.LUN
task.scmd.Tag = uint64(cmd.TaskTag)
task.scmd.RelTargetPortID = task.conn.session.TPGT
task.state = taskSCSI
if task.scmd.OutSDBBuffer.Buffer == nil {
task.scmd.OutSDBBuffer.Buffer = bytes.NewBuffer(cmd.RawData)
}
// add scsi target process queue
err := s.SCSI.AddCommandQueue(task.conn.session.Target.SCSITarget.TID, task.scmd)
if err != nil {

View File

@@ -24,6 +24,7 @@ import (
log "github.com/Sirupsen/logrus"
"github.com/gostor/gotgt/pkg/api"
"github.com/gostor/gotgt/pkg/util"
"github.com/gostor/gotgt/pkg/util/pool"
)
type BaseBackingStore struct {
@@ -53,16 +54,16 @@ func NewBackingStore(name string) (api.BackingStore, error) {
func bsPerformCommand(bs api.BackingStore, cmd *api.SCSICommand) (err error, key byte, asc SCSISubError) {
var (
scb = cmd.SCB.Bytes()
offset = cmd.Offset
opcode = api.SCSICommandType(scb[0])
lu = cmd.Device
wbuf []byte = []byte{}
tl int64 = int64(cmd.TL)
rbuf = make([]byte, tl)
scb = cmd.SCB
offset = cmd.Offset
opcode = api.SCSICommandType(scb[0])
lu = cmd.Device
length int
doVerify bool = false
doWrite bool = false
wbuf []byte
tl int64 = int64(cmd.TL)
rbuf []byte = pool.NewBuffer(int(tl))
)
key = HARDWARE_ERROR
asc = ASC_INTERNAL_TGT_FAILURE
@@ -75,9 +76,10 @@ func bsPerformCommand(bs api.BackingStore, cmd *api.SCSICommand) (err error, key
asc = ASC_READ_ERROR
break
}
cmd.InSDBBuffer.Buffer = bytes.NewBuffer(tmpbuf)
wbuf = cmd.OutSDBBuffer.Buffer.Bytes()
copy(cmd.InSDBBuffer.Buffer, tmpbuf)
if cmd.OutSDBBuffer != nil {
wbuf = cmd.OutSDBBuffer.Buffer
}
doWrite = true
goto write
case api.COMPARE_AND_WRITE:
@@ -91,8 +93,12 @@ func bsPerformCommand(bs api.BackingStore, cmd *api.SCSICommand) (err error, key
break
case api.WRITE_VERIFY, api.WRITE_VERIFY_12, api.WRITE_VERIFY_16:
doVerify = true
fallthrough
case api.WRITE_6, api.WRITE_10, api.WRITE_12, api.WRITE_16:
wbuf = cmd.OutSDBBuffer.Buffer.Bytes()
// For stupid client which does not set WRITE flag
if cmd.OutSDBBuffer != nil {
wbuf = cmd.OutSDBBuffer.Buffer
}
doWrite = true
goto write
case api.WRITE_SAME, api.WRITE_SAME_16:
@@ -113,7 +119,8 @@ func bsPerformCommand(bs api.BackingStore, cmd *api.SCSICommand) (err error, key
if (opcode != api.READ_6) && (scb[1]&0x10 != 0) {
bs.DataAdvise(int64(offset), int64(length), util.POSIX_FADV_NOREUSE)
}
cmd.InSDBBuffer.Buffer = bytes.NewBuffer(rbuf)
cmd.InSDBBuffer.Resid = uint32(length)
copy(cmd.InSDBBuffer.Buffer, rbuf)
case api.PRE_FETCH_10, api.PRE_FETCH_16:
err = bs.DataAdvise(int64(offset), tl, util.POSIX_FADV_WILLNEED)
if err != nil {
@@ -121,6 +128,10 @@ func bsPerformCommand(bs api.BackingStore, cmd *api.SCSICommand) (err error, key
asc = ASC_READ_ERROR
}
case api.VERIFY_10, api.VERIFY_12, api.VERIFY_16:
// For stupid client which does not set WRITE flag
if cmd.OutSDBBuffer != nil {
wbuf = cmd.OutSDBBuffer.Buffer
}
doVerify = true
goto verify
case api.UNMAP:
@@ -138,7 +149,7 @@ write:
asc = ASC_READ_ERROR
goto sense
}
log.Debugf("write data at %d for length %d", offset, len(wbuf))
log.Debugf("write data at 0x%x for length %d", offset, len(wbuf))
var pg *api.ModePage
for _, p := range lu.ModePages {
if p.PageCode == 0x08 && p.SubPageCode == 0 {
@@ -171,11 +182,14 @@ verify:
asc = ASC_READ_ERROR
goto sense
}
if !bytes.Equal(cmd.OutSDBBuffer.Buffer.Bytes(), rbuf) {
err = fmt.Errorf("verify fail between out buffer and read buffer")
if !bytes.Equal(wbuf, rbuf) {
err = fmt.Errorf("verify fail between out buffer[length=%d] and read buffer[length=%d]", len(wbuf), len(rbuf))
key = MISCOMPARE
asc = ASC_MISCOMPARE_DURING_VERIFY_OPERATION
goto sense
} else {
log.Warnf("%v", wbuf)
log.Warnf("%v", rbuf)
}
if scb[1]&0x10 != 0 {
bs.DataAdvise(int64(offset), int64(length), util.POSIX_FADV_WILLNEED)

View File

@@ -83,7 +83,7 @@ func GetReservation(dev *api.SCSILu, nexusID uint64) *api.SCSIReservation {
}
func luPerformCommand(tid int, cmd *api.SCSICommand) api.SAMStat {
op := int(cmd.SCB.Bytes()[0])
op := int(cmd.SCB[0])
fn := cmd.Device.DeviceProtocol.PerformCommand(op)
if fn != nil {
fnop := fn.(SCSIDeviceOperation)

View File

@@ -18,8 +18,6 @@ limitations under the License.
package scsi
import (
"bytes"
"encoding/binary"
"fmt"
"unsafe"
@@ -235,18 +233,11 @@ func SBCModeSense(host int, cmd *api.SCSICommand) api.SAMStat {
deviceSpecific |= 0x80
}
buf := cmd.InSDBBuffer.Buffer
data := []byte{0x00, 0x00, 0x00, 0x00}
if buf != nil {
data = buf.Bytes()
}
if cmd.SCB.Bytes()[0] == 0x1a {
data[2] = deviceSpecific
if cmd.SCB[0] == 0x1a {
cmd.InSDBBuffer.Buffer[2] = deviceSpecific
} else {
data[3] = deviceSpecific
cmd.InSDBBuffer.Buffer[3] = deviceSpecific
}
cmd.InSDBBuffer.Buffer = bytes.NewBuffer(data)
return api.SAMStatGood
}
@@ -284,15 +275,15 @@ func SBCFormatUnit(host int, cmd *api.SCSICommand) api.SAMStat {
goto sense
}
if cmd.SCB.Bytes()[1]&0x80 != 0 {
if cmd.SCB[1]&0x80 != 0 {
// we dont support format protection information
goto sense
}
if cmd.SCB.Bytes()[1]&0x10 != 0 {
if cmd.SCB[1]&0x10 != 0 {
// we dont support format data
goto sense
}
if cmd.SCB.Bytes()[1]&0x07 != 0 {
if cmd.SCB[1]&0x07 != 0 {
// defect list format must be 0
goto sense
}
@@ -330,7 +321,7 @@ func SBCReadWrite(host int, cmd *api.SCSICommand) api.SAMStat {
key = ILLEGAL_REQUEST
asc = ASC_INVALID_FIELD_IN_CDB
dev = cmd.Device
scb = cmd.SCB.Bytes()
scb = cmd.SCB
opcode = api.SCSICommandType(scb[0])
lba uint64
tl uint32
@@ -353,9 +344,6 @@ func SBCReadWrite(host int, cmd *api.SCSICommand) api.SAMStat {
log.Warnf("sense data(ILLEGAL_REQUEST,ASC_INVALID_FIELD_IN_CDB) encounter")
goto sense
}
if cmd.OutSDBBuffer.Buffer == nil {
cmd.OutSDBBuffer.Buffer = &bytes.Buffer{}
}
case api.WRITE_SAME, api.WRITE_SAME_16:
// We dont support resource-provisioning so ANCHOR bit == 1 is an error.
if scb[1]&0x10 != 0 {
@@ -482,10 +470,9 @@ func SBCRelease(host int, cmd *api.SCSICommand) api.SAMStat {
*/
func SBCReadCapacity(host int, cmd *api.SCSICommand) api.SAMStat {
var (
scb = cmd.SCB.Bytes()
scb = cmd.SCB
key = ILLEGAL_REQUEST
asc = ASC_LUN_NOT_SUPPORTED
data = &bytes.Buffer{}
bshift = cmd.Device.BlockShift
size = cmd.Device.Size >> bshift
)
@@ -501,24 +488,21 @@ func SBCReadCapacity(host int, cmd *api.SCSICommand) api.SAMStat {
goto sense
}
/*
if cmd.InSDBBuffer.Length < 8 {
goto overflow
}
*/
if cmd.InSDBBuffer.Length < 8 {
goto overflow
}
// data[0] = (size >> 32) ? __cpu_to_be32(0xffffffff) : __cpu_to_be32(size - 1);
if size>>32 != 0 {
binary.Write(data, binary.BigEndian, uint32(0xffffffff))
copy(cmd.InSDBBuffer.Buffer, util.MarshalUint32(uint32(0xffffffff)))
} else {
binary.Write(data, binary.BigEndian, uint32(size-1))
copy(cmd.InSDBBuffer.Buffer, util.MarshalUint32(uint32(size-1)))
}
// data[1] = __cpu_to_be32(1U << bshift);
binary.Write(data, binary.BigEndian, uint32(1<<bshift))
//overflow:
copy(cmd.InSDBBuffer.Buffer[4:], util.MarshalUint32(uint32(1<<bshift)))
overflow:
cmd.InSDBBuffer.Resid = 8
cmd.InSDBBuffer.Buffer = data
return api.SAMStatGood
sense:
cmd.InSDBBuffer.Resid = 0
@@ -537,7 +521,7 @@ func SBCVerify(host int, cmd *api.SCSICommand) api.SAMStat {
key = ILLEGAL_REQUEST
asc = ASC_INVALID_FIELD_IN_CDB
dev = cmd.Device
scb = cmd.SCB.Bytes()
scb = cmd.SCB
lba uint64
tl uint32
err error
@@ -548,14 +532,14 @@ func SBCVerify(host int, cmd *api.SCSICommand) api.SAMStat {
goto sense
}
if cmd.SCB.Bytes()[1]&0xe0 != 0 {
if scb[1]&0xe0 != 0 {
// We only support protection information type 0
key = ILLEGAL_REQUEST
asc = ASC_INVALID_FIELD_IN_CDB
goto sense
}
if cmd.SCB.Bytes()[1]&0x02 == 0 {
if scb[1]&0x02 == 0 {
// no data compare with the media
return api.SAMStatGood
}
@@ -587,7 +571,6 @@ func SBCVerify(host int, cmd *api.SCSICommand) api.SAMStat {
}
return api.SAMStatGood
sense:
cmd.InSDBBuffer.Resid = 0
BuildSenseData(cmd, key, asc)
return api.SAMStatCheckCondition
}
@@ -602,17 +585,19 @@ sense:
*/
func SBCReadCapacity16(host int, cmd *api.SCSICommand) api.SAMStat {
var (
data = &bytes.Buffer{}
bshift = cmd.Device.BlockShift
size = cmd.Device.Size >> bshift
bshift = cmd.Device.BlockShift
size = cmd.Device.Size >> bshift
allocationLength uint32
)
data.Write(util.MarshalUint64(uint64(size - 1)))
binary.Write(data, binary.BigEndian, uint32(1<<bshift))
val := (cmd.Device.Attrs.Lbppbe << 16) | cmd.Device.Attrs.LowestAlignedLBA
data.Write(util.MarshalUint32(uint32(val)))
binary.Write(data, binary.BigEndian, uint64(0))
binary.Write(data, binary.BigEndian, uint64(0))
cmd.InSDBBuffer.Buffer = data
allocationLength = util.GetUnalignedUint32(cmd.SCB[10:14])
copy(cmd.InSDBBuffer.Buffer, util.MarshalUint64(uint64(size-1)))
if allocationLength > 12 {
copy(cmd.InSDBBuffer.Buffer[8:], util.MarshalUint32(uint32(1<<bshift)))
if allocationLength > 16 {
val := (cmd.Device.Attrs.Lbppbe << 16) | cmd.Device.Attrs.LowestAlignedLBA
copy(cmd.InSDBBuffer.Buffer[12:], util.MarshalUint32(uint32(val)))
}
}
return api.SAMStatGood
}
@@ -621,7 +606,7 @@ func SBCGetLbaStatus(host int, cmd *api.SCSICommand) api.SAMStat {
key = ILLEGAL_REQUEST
asc = ASC_INVALID_FIELD_IN_CDB
dev = cmd.Device
scb = cmd.SCB.Bytes()
scb = cmd.SCB
lba uint64
tl uint32
)
@@ -631,14 +616,14 @@ func SBCGetLbaStatus(host int, cmd *api.SCSICommand) api.SAMStat {
goto sense
}
if cmd.SCB.Bytes()[1]&0xe0 != 0 {
if scb[1]&0xe0 != 0 {
// We only support protection information type 0
key = ILLEGAL_REQUEST
asc = ASC_INVALID_FIELD_IN_CDB
goto sense
}
if cmd.SCB.Bytes()[1]&0x02 == 0 {
if scb[1]&0x02 == 0 {
// no data compare with the media
return api.SAMStatGood
}
@@ -668,7 +653,7 @@ sense:
}
func SBCServiceAction(host int, cmd *api.SCSICommand) api.SAMStat {
opcode := api.SCSICommandType(cmd.SCB.Bytes()[1] & 0x1f)
opcode := api.SCSICommandType(cmd.SCB[1] & 0x1f)
switch opcode {
case api.READ_CAPACITY:
return SBCReadCapacity(host, cmd)

View File

@@ -80,7 +80,7 @@ func (s *SCSITargetService) AddCommandQueue(tid int, scmd *api.SCSICommand) erro
lun := *(*uint64)(unsafe.Pointer(&scmd.Lun))
scmd.Device = target.Devices[lun]
log.Debugf("scsi opcode: 0x%x, LUN: %d", int(scmd.SCB.Bytes()[0]), binary.LittleEndian.Uint64(scmd.Lun[:]))
log.Debugf("scsi opcode: 0x%x, LUN: %d", int(scmd.SCB[0]), binary.LittleEndian.Uint64(scmd.Lun[:]))
if scmd.Device == nil {
scmd.Device = target.LUN0
@@ -91,6 +91,7 @@ func (s *SCSITargetService) AddCommandQueue(tid int, scmd *api.SCSICommand) erro
return nil
}
}
result := scmd.Device.PerformCommand(tid, scmd)
if result != api.SAMStatGood {
scmd.Result = result.Stat
@@ -125,7 +126,8 @@ func NewSCSIDeviceOperation(fn api.CommandFunc, sa []*SCSIServiceAction, pr uint
func BuildSenseData(cmd *api.SCSICommand, key byte, asc SCSISubError) {
senseBuffer := &bytes.Buffer{}
inBufLen, ok := SCSICDBBufXLength(cmd.SCB.Bytes())
inBufLen, ok := SCSICDBBufXLength(cmd.SCB)
var length uint32 = 0xa
if cmd.Device.Attrs.SenseFormat {
// descriptor format
@@ -134,10 +136,9 @@ func BuildSenseData(cmd *api.SCSICommand, key byte, asc SCSISubError) {
senseBuffer.WriteByte(key)
senseBuffer.WriteByte((byte(asc) >> 8) & 0xff)
senseBuffer.WriteByte(byte(asc) & 0xff)
cmd.SenseLength = 8
length = 8
} else {
// fixed format
var length uint32 = 0xa
// current, not deferred
senseBuffer.WriteByte(0x70)
senseBuffer.WriteByte(0x00)
@@ -154,10 +155,10 @@ func BuildSenseData(cmd *api.SCSICommand, key byte, asc SCSISubError) {
for i := 0; i < 4; i++ {
senseBuffer.WriteByte(0x00)
}
cmd.SenseLength = length + 8
length += 8
}
if ok {
if int64(len(senseBuffer.Bytes())) > inBufLen {
if int64(length) > inBufLen {
log.Warnf("sense buffer is bigger than in buffer")
senseBuffer.Truncate(int(inBufLen))
}
@@ -165,7 +166,7 @@ func BuildSenseData(cmd *api.SCSICommand, key byte, asc SCSISubError) {
log.Debugf("cannot calc cbd alloc length. truncate failed")
}
cmd.Result = key
cmd.SenseBuffer = senseBuffer
cmd.SenseBuffer = &api.SenseBuffer{senseBuffer.Bytes(), length}
}
func getSCSIReadWriteOffset(scb []byte) uint64 {

View File

@@ -204,7 +204,7 @@ func SPCInquiry(host int, cmd *api.SCSICommand) api.SAMStat {
addBuf = &bytes.Buffer{}
addBufData []byte = []byte{}
//b byte = 0x75
scb []byte = cmd.SCB.Bytes()
scb []byte = cmd.SCB
pcode byte = scb[2]
evpd bool = false
@@ -227,22 +227,19 @@ func SPCInquiry(host int, cmd *api.SCSICommand) api.SAMStat {
switch pcode {
case 0x00:
buf, _ = InquiryPage0x00(host, cmd)
case 0x80:
buf, _ = InquiryPage0x80(host, cmd)
case 0x83:
buf, _ = InquiryPage0x83(host, cmd)
default:
goto sense
}
data = buf.Bytes()
if int(allocationLength) < len(data) {
cmd.InSDBBuffer.Buffer = bytes.NewBuffer(data[0:allocationLength])
copy(cmd.InSDBBuffer.Buffer, data[0:allocationLength])
cmd.InSDBBuffer.Resid = uint32(len(data))
} else {
cmd.InSDBBuffer.Buffer = bytes.NewBuffer(data[0:])
copy(cmd.InSDBBuffer.Buffer, data[0:])
}
} else {
if pcode != 0 {
@@ -304,9 +301,11 @@ func SPCInquiry(host int, cmd *api.SCSICommand) api.SAMStat {
buf.Write(addBufData)
data = buf.Bytes()
if allocationLength < uint16(additionLength) {
cmd.InSDBBuffer.Buffer = bytes.NewBuffer(data[0:allocationLength])
cmd.InSDBBuffer.Resid = uint32(allocationLength)
copy(cmd.InSDBBuffer.Buffer, data[0:allocationLength])
} else {
cmd.InSDBBuffer.Buffer = bytes.NewBuffer(data[0:])
cmd.InSDBBuffer.Resid = uint32(len(data))
copy(cmd.InSDBBuffer.Buffer, data[0:])
}
}
@@ -331,10 +330,9 @@ func SPCReportLuns(host int, cmd *api.SCSICommand) api.SAMStat {
availLength uint32 = 0
allocationLength uint32
buf *bytes.Buffer = &bytes.Buffer{}
scb *bytes.Buffer = cmd.SCB
)
// Get Allocation Length
allocationLength = util.GetUnalignedUint32(scb.Bytes()[6:10])
allocationLength = util.GetUnalignedUint32(cmd.SCB[6:10])
if allocationLength < 16 {
log.Warn("goto sense, allocationLength < 16")
goto sense
@@ -376,7 +374,7 @@ func SPCReportLuns(host int, cmd *api.SCSICommand) api.SAMStat {
}
}
cmd.InSDBBuffer.Buffer = buf
copy(cmd.InSDBBuffer.Buffer, buf.Bytes())
return api.SAMStatGood
sense:
cmd.InSDBBuffer.Resid = 0
@@ -393,7 +391,7 @@ func SPCStartStop(host int, cmd *api.SCSICommand) api.SAMStat {
}
cmd.InSDBBuffer.Resid = 0
scb := cmd.SCB.Bytes()
scb := cmd.SCB
pwrcnd = scb[4] & 0xf0
if pwrcnd != 0 {
return api.SAMStatGood
@@ -452,7 +450,7 @@ func SPCPreventAllowMediaRemoval(host int, cmd *api.SCSICommand) api.SAMStat {
return api.SAMStatReservationConflict
}
// PREVENT_MASK = 0x03
cmd.ITNexusLuInfo.Prevent = int(cmd.SCB.Bytes()[4] & 0x03)
cmd.ITNexusLuInfo.Prevent = int(cmd.SCB[4] & 0x03)
return api.SAMStatGood
}
@@ -467,7 +465,7 @@ func SPCPreventAllowMediaRemoval(host int, cmd *api.SCSICommand) api.SAMStat {
*/
func SPCModeSense(host int, cmd *api.SCSICommand) api.SAMStat {
var (
scb = cmd.SCB.Bytes()
scb = cmd.SCB
mode6 = (scb[0] == 0x1a)
dbd = scb[1] & 0x8 // Disable Block Descriptors
pcode = scb[2] & 0x3f
@@ -574,7 +572,7 @@ func SPCModeSense(host int, cmd *api.SCSICommand) api.SAMStat {
if rlen := uint32(len(data)); rlen < allocLen {
cmd.InSDBBuffer.Resid = rlen
}
cmd.InSDBBuffer.Buffer = bytes.NewBuffer(data)
copy(cmd.InSDBBuffer.Buffer, data)
return api.SAMStatGood
sense:
BuildSenseData(cmd, key, asc)
@@ -591,7 +589,7 @@ sense:
*/
func SPCSendDiagnostics(host int, cmd *api.SCSICommand) api.SAMStat {
// we only support SELF-TEST==1
if cmd.SCB.Bytes()[1]&0x04 == 0 {
if cmd.SCB[1]&0x04 == 0 {
goto sense
}
@@ -640,9 +638,8 @@ func reportOpcodesAll(cmd *api.SCSICommand, rctd int) error {
}
}
}
buf := util.MarshalUint32(uint32(len(data) - 4))
buf = append(buf, data[4:]...)
cmd.InSDBBuffer.Buffer = bytes.NewBuffer(buf)
copy(cmd.InSDBBuffer.Buffer, util.MarshalUint32(uint32(len(data)-4)))
copy(cmd.InSDBBuffer.Buffer[4:], data[4:])
return nil
}
@@ -651,7 +648,7 @@ func reportOpcodeOne(cmd *api.SCSICommand, rctd int, opcode byte, rsa uint16, se
}
func SPCReportSupportedOperationCodes(host int, cmd *api.SCSICommand) api.SAMStat {
scb := cmd.SCB.Bytes()
scb := cmd.SCB
reporting_options := scb[2] & 0x07
opcode := scb[3]
rctd := int(scb[2] & 0x80)
@@ -692,54 +689,43 @@ sense:
// This is useful for the various commands using the SERVICE ACTION format.
func SPCServiceAction(host int, cmd *api.SCSICommand) api.SAMStat {
scb := cmd.SCB.Bytes()
scb := cmd.SCB
opcode := int(scb[0])
action := uint8(scb[1] & 0x1F)
serviceAction := cmd.Device.DeviceProtocol.PerformServiceAction(opcode, action)
if serviceAction == nil {
cmd.InSDBBuffer.Resid = 0
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
return api.SAMStatCheckCondition
} else {
if serviceAction != nil {
fnop := serviceAction.(*SCSIServiceAction)
return fnop.CommandPerformFunc(host, cmd)
}
cmd.InSDBBuffer.Resid = 0
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
return api.SAMStatCheckCondition
}
func SPCPRReadKeys(host int, cmd *api.SCSICommand) api.SAMStat {
var (
buf = &bytes.Buffer{}
data []byte = []byte{}
addBuf = &bytes.Buffer{}
addBuf []byte = []byte{}
allocationLength uint16
additionLength uint32
l int = 0
)
tgtName := cmd.Target.Name
devUUID := cmd.Device.UUID
scsiResOp := GetSCSIReservationOperator()
PRGeneration, _ := scsiResOp.GetPRGeneration(tgtName, devUUID)
resList := scsiResOp.GetReservationList(tgtName, devUUID)
length, _ := SCSICDBBufXLength(cmd.SCB.Bytes())
allocationLength = uint16(length)
if allocationLength < 8 {
goto sense
}
for _, res := range resList {
addBuf.Write(util.MarshalUint64(res.Key))
addBuf = append(addBuf, util.MarshalUint64(res.Key)...)
}
additionLength = uint32(len(addBuf.Bytes()))
additionLength = uint32(len(addBuf))
buf.Write(util.MarshalUint32(PRGeneration))
buf.Write(util.MarshalUint32(additionLength))
buf.Write(addBuf.Bytes())
data = buf.Bytes()
if allocationLength < uint16(additionLength) {
cmd.InSDBBuffer.Buffer = bytes.NewBuffer(data[0:allocationLength])
} else {
cmd.InSDBBuffer.Buffer = bytes.NewBuffer(data)
}
l += copy(cmd.InSDBBuffer.Buffer[l:], util.MarshalUint32(PRGeneration))
l += copy(cmd.InSDBBuffer.Buffer[l:], util.MarshalUint32(additionLength))
l += copy(cmd.InSDBBuffer.Buffer[l:], addBuf)
cmd.InSDBBuffer.Resid = uint32(additionLength)
return api.SAMStatGood
@@ -763,7 +749,7 @@ func SPCPRReadReservation(host int, cmd *api.SCSICommand) api.SAMStat {
PRGeneration, _ := scsiResOp.GetPRGeneration(tgtName, devUUID)
curRes := scsiResOp.GetCurrentReservation(tgtName, devUUID)
length, _ := SCSICDBBufXLength(cmd.SCB.Bytes())
length, _ := SCSICDBBufXLength(cmd.SCB)
allocationLength = uint16(length)
if allocationLength < 8 {
goto sense
@@ -791,9 +777,9 @@ func SPCPRReadReservation(host int, cmd *api.SCSICommand) api.SAMStat {
buf.Write(addBuf.Bytes())
data = buf.Bytes()
if allocationLength < uint16(additionLength) {
cmd.InSDBBuffer.Buffer = bytes.NewBuffer(data[0:allocationLength])
copy(cmd.InSDBBuffer.Buffer, data[0:allocationLength])
} else {
cmd.InSDBBuffer.Buffer = bytes.NewBuffer(data)
copy(cmd.InSDBBuffer.Buffer, data)
}
cmd.InSDBBuffer.Resid = uint32(additionLength)
@@ -807,40 +793,34 @@ sense:
func SPCPRReportCapabilities(host int, cmd *api.SCSICommand) api.SAMStat {
var (
buf []byte = make([]byte, 8)
availLength uint32 = 8
actualLength uint32 = 0
data *bytes.Buffer = cmd.InSDBBuffer.Buffer
availLength uint32 = 8
actualLength uint32 = 0
)
allocationLength := uint32(util.GetUnalignedUint16(cmd.SCB.Bytes()[7:9]))
allocationLength := uint32(util.GetUnalignedUint16(cmd.SCB[7:9]))
if allocationLength < 8 {
goto sense
}
if cmd.InSDBBuffer.Length < allocationLength {
goto sense
}
binary.BigEndian.PutUint16(buf[0:2], uint16(8))
copy(cmd.InSDBBuffer.Buffer, util.MarshalUint16(uint16(8)))
// Persistent Reservation Type Mask format
// Type Mask Valid (TMV)
buf[3] |= 0x80
cmd.InSDBBuffer.Buffer[3] |= 0x80
// PR_TYPE_EXCLUSIVE_ACCESS_ALLREG
buf[4] |= 0x80
cmd.InSDBBuffer.Buffer[4] |= 0x80
// PR_TYPE_EXCLUSIVE_ACCESS_REGONLY
buf[4] |= 0x40
cmd.InSDBBuffer.Buffer[4] |= 0x40
// PR_TYPE_WRITE_EXCLUSIVE_REGONLY
buf[4] |= 0x20
cmd.InSDBBuffer.Buffer[4] |= 0x20
// PR_TYPE_EXCLUSIVE_ACCESS
buf[4] |= 0x08
cmd.InSDBBuffer.Buffer[4] |= 0x08
// PR_TYPE_WRITE_EXCLUSIVE
buf[4] |= 0x02
cmd.InSDBBuffer.Buffer[4] |= 0x02
// PR_TYPE_EXCLUSIVE_ACCESS_ALLREG
buf[5] |= 0x01
cmd.InSDBBuffer.Buffer[5] |= 0x01
if err := binary.Write(data, binary.BigEndian, buf); err != nil {
goto sense
} else {
actualLength = availLength
}
actualLength = availLength
cmd.InSDBBuffer.Resid = uint32(actualLength)
return api.SAMStatGood
sense:
@@ -852,9 +832,9 @@ sense:
func reservationCheck(host int, cmd *api.SCSICommand) bool {
var (
paramLen uint32
buf []byte = cmd.OutSDBBuffer.Buffer.Bytes()
buf []byte = cmd.OutSDBBuffer.Buffer
)
length, _ := SCSICDBBufXLength(cmd.SCB.Bytes())
length, _ := SCSICDBBufXLength(cmd.SCB)
paramLen = uint32(length)
if paramLen != 24 {
return false
@@ -871,8 +851,8 @@ func reservationCheck(host int, cmd *api.SCSICommand) bool {
func SPCPRRegister(host int, cmd *api.SCSICommand) api.SAMStat {
var (
buf []byte = cmd.OutSDBBuffer.Buffer.Bytes()
scb []byte = cmd.SCB.Bytes()
buf []byte = cmd.OutSDBBuffer.Buffer
scb []byte = cmd.SCB
ignoreKey bool = false
ok bool = false
resKey uint64
@@ -930,7 +910,7 @@ sense:
func SPCPRReserve(host int, cmd *api.SCSICommand) api.SAMStat {
var (
scb []byte = cmd.SCB.Bytes()
scb []byte = cmd.SCB
curRes *api.SCSIReservation
res *api.SCSIReservation
ok bool = false
@@ -992,8 +972,8 @@ sense:
func SPCPRRelease(host int, cmd *api.SCSICommand) api.SAMStat {
var (
buf []byte = cmd.OutSDBBuffer.Buffer.Bytes()
scb []byte = cmd.SCB.Bytes()
buf []byte = cmd.OutSDBBuffer.Buffer
scb []byte = cmd.SCB
curRes *api.SCSIReservation
res *api.SCSIReservation
resList []*api.SCSIReservation
@@ -1073,7 +1053,7 @@ sense:
func SPCPRClear(host int, cmd *api.SCSICommand) api.SAMStat {
var (
buf []byte = cmd.OutSDBBuffer.Buffer.Bytes()
buf []byte = cmd.OutSDBBuffer.Buffer
curRes *api.SCSIReservation
res *api.SCSIReservation
ok bool = false
@@ -1127,8 +1107,8 @@ sense:
func SPCPRPreempt(host int, cmd *api.SCSICommand) api.SAMStat {
var (
buf []byte = cmd.OutSDBBuffer.Buffer.Bytes()
scb []byte = cmd.SCB.Bytes()
buf []byte = cmd.OutSDBBuffer.Buffer
scb []byte = cmd.SCB
ok bool = false
resKey uint64
sAResKey uint64
@@ -1227,8 +1207,8 @@ sense:
func SPCPRRegisterAndMove(host int, cmd *api.SCSICommand) api.SAMStat {
var (
buf []byte = cmd.OutSDBBuffer.Buffer.Bytes()
scb []byte = cmd.SCB.Bytes()
buf []byte = cmd.OutSDBBuffer.Buffer
scb []byte = cmd.SCB
resKey uint64
sAResKey uint64
curRes, dstReg, res *api.SCSIReservation
@@ -1322,28 +1302,23 @@ func SPCRequestSense(host int, cmd *api.SCSICommand) api.SAMStat {
var (
allocationLength uint32
actualLength uint32
data = &bytes.Buffer{}
)
allocationLength = util.GetUnalignedUint32(cmd.SCB.Bytes()[4:8])
allocationLength = util.GetUnalignedUint32(cmd.SCB[4:8])
if allocationLength > cmd.InSDBBuffer.Length {
allocationLength = cmd.InSDBBuffer.Length
}
BuildSenseData(cmd, NO_SENSE, NO_ADDITIONAL_SENSE)
if cmd.SenseLength < allocationLength {
actualLength = cmd.SenseLength
if cmd.SenseBuffer.Length < allocationLength {
actualLength = cmd.SenseBuffer.Length
} else {
actualLength = allocationLength
}
if cmd.SenseBuffer != nil {
data.Write(cmd.SenseBuffer.Bytes()[:actualLength])
}
copy(cmd.InSDBBuffer.Buffer, cmd.SenseBuffer.Buffer[:actualLength])
cmd.InSDBBuffer.Resid = uint32(actualLength)
cmd.InSDBBuffer.Buffer = data
// reset sense buffer in cmnd
cmd.SenseBuffer = &bytes.Buffer{}
cmd.SenseLength = 0
cmd.SenseBuffer = &api.SenseBuffer{}
return api.SAMStatGood
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2016 The GoStor Authors All rights reserved.
Copyright 2017 The GoStor Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -35,26 +35,28 @@ func TestSPCReportLuns(t *testing.T) {
target := new(api.SCSITarget)
target.Devices = map[uint64]*api.SCSILu{0: lu}
cmd.Target = target
cmd.SCB = &bytes.Buffer{}
cmd.SenseBuffer = &bytes.Buffer{}
scb := &bytes.Buffer{}
cmd.InSDBBuffer = &api.SCSIDataBuffer{}
cmd.InSDBBuffer.Length = 16
cmd.InSDBBuffer.Buffer = &bytes.Buffer{}
cmd.SCB.WriteByte(byte(api.REPORT_LUNS))
cmd.InSDBBuffer.Buffer = []byte{}
scb.WriteByte(byte(api.REPORT_LUNS))
for i := 0; i < 5; i++ {
cmd.SCB.WriteByte(0x00)
scb.WriteByte(0x00)
}
binary.Write(cmd.SCB, binary.BigEndian, uint32(16))
binary.Write(scb, binary.BigEndian, uint32(16))
cmd.SCB = scb.Bytes()
if err := SPCReportLuns(0, cmd); err.Err != nil {
t.Errorf("Expected not error, but got %v", err)
}
cmd.SCB = &bytes.Buffer{}
cmd.SCB.WriteByte(byte(api.REPORT_LUNS))
scb = &bytes.Buffer{}
scb.WriteByte(byte(api.REPORT_LUNS))
for i := 0; i < 5; i++ {
cmd.SCB.WriteByte(0x00)
scb.WriteByte(0x00)
}
binary.Write(cmd.SCB, binary.BigEndian, uint32(10))
binary.Write(scb, binary.BigEndian, uint32(10))
cmd.SCB = scb.Bytes()
if err := SPCReportLuns(0, cmd); err.Err == nil {
t.Error("Expected error, but got nothing")
}

30
pkg/util/pool/pool.go Normal file
View File

@@ -0,0 +1,30 @@
/*
Copyright 2017 The GoStor Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package pool provides memory pool for buffer.
package pool
import "sync"
func NewBuffer(size int) []byte {
var bytePool = sync.Pool{
New: func() interface{} {
return make([]byte, size)
},
}
return bytePool.Get().([]byte)
}

View File

@@ -73,6 +73,15 @@ func MarshalKVText(kv []KeyValue) []byte {
return data
}
func MarshalUint16(i uint16) []byte {
var data []byte
for j := 8; j >= 0; j -= 8 {
b := byte(i >> uint16(j))
data = append(data, b)
}
return data
}
func MarshalUint32(i uint32) []byte {
var data []byte
for j := 24; j >= 0; j -= 8 {