@@ -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
|
||||
}
|
||||
|
||||
@@ -278,7 +278,7 @@ func parseHeader(data []byte) (*ISCSICommand, error) {
|
||||
|
||||
func (m *ISCSICommand) scsiCmdRespBytes() []byte {
|
||||
// rfc7143 11.4
|
||||
buf := &bytes.Buffer{}
|
||||
buf := bytes.Buffer{}
|
||||
buf.WriteByte(byte(OpSCSIResp))
|
||||
var flag byte = 0x80
|
||||
if m.Resid > 0 {
|
||||
@@ -321,8 +321,12 @@ func (m *ISCSICommand) scsiCmdRespBytes() []byte {
|
||||
|
||||
func (m *ISCSICommand) dataInBytes() []byte {
|
||||
// rfc7143 11.7
|
||||
buf := &bytes.Buffer{}
|
||||
buf.WriteByte(byte(OpSCSIIn))
|
||||
dl := m.DataLen
|
||||
for dl%4 > 0 {
|
||||
dl++
|
||||
}
|
||||
var buf = make([]byte, (48 + dl))
|
||||
buf[0] = byte(OpSCSIIn)
|
||||
var flag byte
|
||||
if m.FinalInSeq || m.Final == true {
|
||||
flag |= 0x80
|
||||
@@ -334,48 +338,33 @@ 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
|
||||
}
|
||||
}
|
||||
buf.WriteByte(flag)
|
||||
buf.WriteByte(0x00)
|
||||
buf[1] = flag
|
||||
//buf.WriteByte(0x00)
|
||||
if m.HasStatus && m.Final == true {
|
||||
flag = byte(m.Status)
|
||||
}
|
||||
buf.WriteByte(flag)
|
||||
|
||||
buf.WriteByte(0x00) // 4
|
||||
|
||||
buf.Write(util.MarshalUint64(uint64(m.DataLen))[5:]) // 5-8
|
||||
//buf.WriteByte(flag)
|
||||
buf[3] = flag
|
||||
copy(buf[5:], util.MarshalUint64(uint64(m.DataLen))[5:])
|
||||
// Skip through to byte 16 Since A bit is not set 11.7.4
|
||||
for i := 0; i < 8; i++ {
|
||||
buf.WriteByte(0x00)
|
||||
}
|
||||
buf.Write(util.MarshalUint64(uint64(m.TaskTag))[4:])
|
||||
for i := 0; i < 4; i++ {
|
||||
// 11.7.4
|
||||
buf.WriteByte(0xff)
|
||||
}
|
||||
buf.Write(util.MarshalUint64(uint64(m.StatSN))[4:])
|
||||
buf.Write(util.MarshalUint64(uint64(m.ExpCmdSN))[4:])
|
||||
buf.Write(util.MarshalUint64(uint64(m.MaxCmdSN))[4:])
|
||||
buf.Write(util.MarshalUint64(uint64(m.DataSN))[4:])
|
||||
buf.Write(util.MarshalUint64(uint64(m.BufferOffset))[4:])
|
||||
buf.Write(util.MarshalUint64(uint64(m.Resid))[4:])
|
||||
buf.Write(m.RawData[m.BufferOffset : m.BufferOffset+uint32(m.DataLen)])
|
||||
dl := m.DataLen
|
||||
for dl%4 > 0 {
|
||||
dl++
|
||||
buf.WriteByte(0x00)
|
||||
}
|
||||
copy(buf[16:], util.MarshalUint32(m.TaskTag))
|
||||
copy(buf[24:], util.MarshalUint32(m.StatSN))
|
||||
copy(buf[28:], util.MarshalUint32(m.ExpCmdSN))
|
||||
copy(buf[32:], util.MarshalUint32(m.MaxCmdSN))
|
||||
copy(buf[36:], util.MarshalUint32(m.DataSN))
|
||||
copy(buf[40:], util.MarshalUint32(m.BufferOffset))
|
||||
copy(buf[44:], util.MarshalUint32(m.Resid))
|
||||
copy(buf[48:], m.RawData[m.BufferOffset:m.BufferOffset+uint32(m.DataLen)])
|
||||
|
||||
return buf.Bytes()
|
||||
return buf
|
||||
}
|
||||
|
||||
func (m *ISCSICommand) textRespBytes() []byte {
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
buf := bytes.Buffer{}
|
||||
buf.WriteByte(byte(OpTextResp))
|
||||
var b byte
|
||||
if m.Final {
|
||||
@@ -415,8 +404,7 @@ func (m *ISCSICommand) textRespBytes() []byte {
|
||||
}
|
||||
|
||||
func (m *ISCSICommand) noopInBytes() []byte {
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
buf := bytes.Buffer{}
|
||||
buf.WriteByte(byte(OpNoopIn))
|
||||
var b byte
|
||||
b |= 0x80
|
||||
@@ -452,7 +440,7 @@ func (m *ISCSICommand) noopInBytes() []byte {
|
||||
|
||||
func (m *ISCSICommand) scsiTMFRespBytes() []byte {
|
||||
// rfc7143 11.6
|
||||
buf := &bytes.Buffer{}
|
||||
buf := bytes.Buffer{}
|
||||
buf.WriteByte(byte(OpSCSITaskResp))
|
||||
buf.WriteByte(0x80)
|
||||
buf.WriteByte(m.Result)
|
||||
@@ -477,9 +465,8 @@ func (m *ISCSICommand) scsiTMFRespBytes() []byte {
|
||||
}
|
||||
|
||||
func (m *ISCSICommand) r2tRespBytes() []byte {
|
||||
|
||||
// rfc7143 11.8
|
||||
buf := &bytes.Buffer{}
|
||||
buf := bytes.Buffer{}
|
||||
buf.WriteByte(byte(OpReady))
|
||||
var b byte
|
||||
if m.Final {
|
||||
|
||||
@@ -125,13 +125,12 @@ func (c *iscsiConnection) init() {
|
||||
sort.Sort(c.loginParam.sessionParam)
|
||||
}
|
||||
|
||||
func (c *iscsiConnection) readData(size int) ([]byte, int, error) {
|
||||
var buf = make([]byte, size)
|
||||
func (c *iscsiConnection) readData(buf []byte) (int, error) {
|
||||
length, err := io.ReadFull(c.conn, buf)
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
return -1, err
|
||||
}
|
||||
return buf, length, nil
|
||||
return length, nil
|
||||
}
|
||||
|
||||
func (c *iscsiConnection) write(resp []byte) (int, error) {
|
||||
@@ -154,7 +153,7 @@ func (conn *iscsiConnection) buildRespPackage(oc OpCode, task *iscsiTask) error
|
||||
if task == nil {
|
||||
task = conn.rxTask
|
||||
}
|
||||
resp := &ISCSICommand{
|
||||
conn.resp = &ISCSICommand{
|
||||
StatSN: conn.req.ExpStatSN,
|
||||
TaskTag: conn.req.TaskTag,
|
||||
ExpCmdSN: conn.session.ExpCmdSN,
|
||||
@@ -163,52 +162,55 @@ func (conn *iscsiConnection) buildRespPackage(oc OpCode, task *iscsiTask) error
|
||||
}
|
||||
switch oc {
|
||||
case OpReady:
|
||||
resp.OpCode = OpReady
|
||||
resp.R2TSN = task.r2tSN
|
||||
resp.BufferOffset = uint32(task.offset)
|
||||
resp.DesiredLength = uint32(task.r2tCount)
|
||||
conn.resp.OpCode = OpReady
|
||||
conn.resp.R2TSN = task.r2tSN
|
||||
conn.resp.BufferOffset = uint32(task.offset)
|
||||
conn.resp.DesiredLength = uint32(task.r2tCount)
|
||||
if val := conn.loginParam.sessionParam[ISCSI_PARAM_MAX_BURST].Value; task.r2tCount > int(val) {
|
||||
resp.DesiredLength = uint32(val)
|
||||
conn.resp.DesiredLength = uint32(val)
|
||||
}
|
||||
case OpSCSIIn, OpSCSIResp:
|
||||
resp.OpCode = oc
|
||||
resp.Immediate = true
|
||||
resp.Final = true
|
||||
resp.SCSIResponse = 0x00
|
||||
resp.HasStatus = true
|
||||
conn.resp.OpCode = oc
|
||||
conn.resp.Immediate = true
|
||||
conn.resp.Final = true
|
||||
conn.resp.SCSIResponse = 0x00
|
||||
conn.resp.HasStatus = true
|
||||
scmd := task.scmd
|
||||
resp.Status = scmd.Result
|
||||
conn.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)
|
||||
conn.resp.RawData = append(length[2:4], scmd.SenseBuffer.Buffer...)
|
||||
} else if scmd.Direction == api.SCSIDataRead || scmd.Direction == api.SCSIDataWrite {
|
||||
if scmd.InSDBBuffer.Buffer != nil {
|
||||
resp.Resid = scmd.InSDBBuffer.Resid
|
||||
buf := scmd.InSDBBuffer.Buffer.Bytes()
|
||||
resp.RawData = buf
|
||||
if scmd.InSDBBuffer != nil {
|
||||
conn.resp.Resid = scmd.InSDBBuffer.Resid
|
||||
if conn.resp.Resid != 0 && conn.resp.Resid < scmd.InSDBBuffer.Length {
|
||||
conn.resp.RawData = scmd.InSDBBuffer.Buffer[:conn.resp.Resid]
|
||||
} else {
|
||||
conn.resp.RawData = scmd.InSDBBuffer.Buffer
|
||||
}
|
||||
} else {
|
||||
resp.RawData = []byte{}
|
||||
conn.resp.RawData = []byte{}
|
||||
}
|
||||
}
|
||||
|
||||
case OpNoopIn, OpReject:
|
||||
resp.OpCode = oc
|
||||
resp.Final = true
|
||||
resp.NSG = FullFeaturePhase
|
||||
resp.ExpCmdSN = conn.req.CmdSN + 1
|
||||
conn.resp.OpCode = oc
|
||||
conn.resp.Final = true
|
||||
conn.resp.NSG = FullFeaturePhase
|
||||
conn.resp.ExpCmdSN = conn.req.CmdSN + 1
|
||||
case OpSCSITaskResp:
|
||||
resp.OpCode = oc
|
||||
resp.Final = true
|
||||
resp.NSG = FullFeaturePhase
|
||||
resp.ExpCmdSN = conn.req.CmdSN + 1
|
||||
resp.Result = task.result
|
||||
conn.resp.OpCode = oc
|
||||
conn.resp.Final = true
|
||||
conn.resp.NSG = FullFeaturePhase
|
||||
conn.resp.ExpCmdSN = conn.req.CmdSN + 1
|
||||
conn.resp.Result = task.result
|
||||
case OpLoginResp:
|
||||
resp.OpCode = OpLoginResp
|
||||
resp.Transit = conn.loginParam.tgtTrans
|
||||
resp.CSG = conn.req.CSG
|
||||
resp.NSG = conn.loginParam.tgtNSG
|
||||
resp.ExpCmdSN = conn.req.CmdSN
|
||||
resp.MaxCmdSN = conn.req.CmdSN
|
||||
conn.resp.OpCode = OpLoginResp
|
||||
conn.resp.Transit = conn.loginParam.tgtTrans
|
||||
conn.resp.CSG = conn.req.CSG
|
||||
conn.resp.NSG = conn.loginParam.tgtNSG
|
||||
conn.resp.ExpCmdSN = conn.req.CmdSN
|
||||
conn.resp.MaxCmdSN = conn.req.CmdSN
|
||||
negoKeys, err := conn.processLoginData()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -217,11 +219,10 @@ func (conn *iscsiConnection) buildRespPackage(oc OpCode, task *iscsiTask) error
|
||||
negoKeys = loginKVDeclare(conn, negoKeys)
|
||||
conn.loginParam.keyDeclared = true
|
||||
}
|
||||
resp.RawData = util.MarshalKVText(negoKeys)
|
||||
conn.resp.RawData = util.MarshalKVText(negoKeys)
|
||||
conn.txTask = nil
|
||||
}
|
||||
|
||||
conn.resp = resp
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -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 (
|
||||
@@ -156,7 +156,6 @@ func (s *ISCSITargetDriver) Run() error {
|
||||
log.Error(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
for {
|
||||
log.Info("Listening ...")
|
||||
@@ -178,6 +177,7 @@ func (s *ISCSITargetDriver) Run() error {
|
||||
// start a new thread to do with this command
|
||||
go s.handler(DATAIN, iscsiConn)
|
||||
}
|
||||
l.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
length, err = conn.readData(buf)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
@@ -224,7 +227,6 @@ func (s *ISCSITargetDriver) rxHandler(conn *iscsiConnection) {
|
||||
conn.state = CONN_STATE_CLOSE
|
||||
return
|
||||
}
|
||||
conn.rxBuffer = buf
|
||||
cmd, err = parseHeader(buf)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
@@ -237,8 +239,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,16 +258,15 @@ 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)
|
||||
l, err := conn.readData(cmd.RawData[length:])
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
length += l
|
||||
buf = append(buf, b...)
|
||||
}
|
||||
if length != dl {
|
||||
log.Debugf("get length is %d, but expected %d", length, dl)
|
||||
@@ -271,10 +274,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
|
||||
@@ -474,10 +474,12 @@ SendRemainingData:
|
||||
for {
|
||||
switch conn.txIOState {
|
||||
case IOSTATE_TX_BHS:
|
||||
log.Debug("ready to write response")
|
||||
log.Debugf("response is %s", resp.String())
|
||||
if log.GetLevel() == log.DebugLevel {
|
||||
log.Debug("ready to write response")
|
||||
log.Debugf("response is %s", resp.String())
|
||||
}
|
||||
if l, err := conn.write(resp.Bytes()); err != nil {
|
||||
log.Error(err)
|
||||
log.Errorf("failed to write data to client: %v", err)
|
||||
return
|
||||
} else {
|
||||
conn.txIOState = IOSTATE_TX_INIT_AHS
|
||||
@@ -536,7 +538,7 @@ SendRemainingData:
|
||||
case CONN_STATE_SCSI:
|
||||
conn.txTask = nil
|
||||
default:
|
||||
log.Warnf("unexpected connection state: %d", conn.state)
|
||||
log.Warnf("unexpected connection state: %v", conn.State())
|
||||
conn.rxIOState = IOSTATE_RX_BHS
|
||||
s.handler(DATAIN, conn)
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,15 @@ 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)
|
||||
length int
|
||||
doVerify bool = false
|
||||
doWrite bool = false
|
||||
scb = cmd.SCB
|
||||
offset = cmd.Offset
|
||||
opcode = api.SCSICommandType(scb[0])
|
||||
lu = cmd.Device
|
||||
length int
|
||||
doVerify bool = false
|
||||
doWrite bool = false
|
||||
rbuf, wbuf []byte
|
||||
tl int64 = int64(cmd.TL)
|
||||
)
|
||||
key = HARDWARE_ERROR
|
||||
asc = ASC_INTERNAL_TGT_FAILURE
|
||||
@@ -75,9 +75,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,14 +92,19 @@ 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:
|
||||
// TODO
|
||||
break
|
||||
case api.READ_6, api.READ_10, api.READ_12, api.READ_16:
|
||||
rbuf = pool.NewBuffer(int(tl))
|
||||
rbuf, err = bs.Read(int64(offset), tl)
|
||||
if err != nil && err != io.EOF {
|
||||
key = MEDIUM_ERROR
|
||||
@@ -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:
|
||||
@@ -130,7 +141,6 @@ func bsPerformCommand(bs api.BackingStore, cmd *api.SCSICommand) (err error, key
|
||||
}
|
||||
write:
|
||||
if doWrite {
|
||||
// hack: wbuf = []byte("hello world!")
|
||||
err = bs.Write(wbuf, int64(offset))
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
@@ -138,7 +148,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 {
|
||||
@@ -165,14 +175,15 @@ write:
|
||||
}
|
||||
verify:
|
||||
if doVerify {
|
||||
rbuf = pool.NewBuffer(int(tl))
|
||||
rbuf, err = bs.Read(int64(offset), tl)
|
||||
if err != nil {
|
||||
key = MEDIUM_ERROR
|
||||
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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
147
pkg/scsi/spc.go
147
pkg/scsi/spc.go
@@ -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
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
34
pkg/util/pool/pool.go
Normal file
34
pkg/util/pool/pool.go
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
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"
|
||||
|
||||
var bytePool sync.Pool = sync.Pool{}
|
||||
|
||||
func NewBuffer(size int) []byte {
|
||||
bytePool.New = func() interface{} {
|
||||
return make([]byte, size)
|
||||
}
|
||||
|
||||
return bytePool.Get().([]byte)
|
||||
}
|
||||
|
||||
func ReleaseBuffer(b []byte) {
|
||||
bytePool.Put(b)
|
||||
}
|
||||
@@ -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 {
|
||||
@@ -82,13 +91,14 @@ func MarshalUint32(i uint32) []byte {
|
||||
return data
|
||||
}
|
||||
|
||||
func MarshalUint64(i uint64) []byte {
|
||||
var data []byte
|
||||
func MarshalUint64(v uint64) []byte {
|
||||
var data = [8]byte{}
|
||||
var i = 0
|
||||
for j := 56; j >= 0; j -= 8 {
|
||||
b := byte(i >> uint32(j))
|
||||
data = append(data, b)
|
||||
data[i] = byte(v >> uint32(j))
|
||||
i++
|
||||
}
|
||||
return data
|
||||
return data[0:8]
|
||||
}
|
||||
|
||||
func StringToByte(str string, align int, maxlength int) []byte {
|
||||
|
||||
Reference in New Issue
Block a user