Merge pull request #93 from utkarshmani1997/jiva-integration
integrate openebs/jiva with gotgt
This commit is contained in:
@@ -17,6 +17,7 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"io"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
uuid "github.com/satori/go.uuid"
|
uuid "github.com/satori/go.uuid"
|
||||||
@@ -165,6 +166,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type SCSICommand struct {
|
type SCSICommand struct {
|
||||||
|
OpCode byte
|
||||||
Target *SCSITarget
|
Target *SCSITarget
|
||||||
DeviceID uint64
|
DeviceID uint64
|
||||||
Device *SCSILu
|
Device *SCSILu
|
||||||
@@ -395,6 +397,9 @@ type SCSILu struct {
|
|||||||
Storage BackingStore
|
Storage BackingStore
|
||||||
DeviceProtocol SCSIDeviceProtocol
|
DeviceProtocol SCSIDeviceProtocol
|
||||||
ModeBlockDescriptor []byte
|
ModeBlockDescriptor []byte
|
||||||
|
SCSIVendorID string
|
||||||
|
SCSIProductID string
|
||||||
|
SCSIID string
|
||||||
|
|
||||||
PerformCommand CommandFunc
|
PerformCommand CommandFunc
|
||||||
FinishCommand func(*SCSITarget, *SCSICommand)
|
FinishCommand func(*SCSITarget, *SCSICommand)
|
||||||
@@ -406,3 +411,14 @@ type UnmapBlockDescriptor struct {
|
|||||||
Offset uint64
|
Offset uint64
|
||||||
TL uint32
|
TL uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ReaderWriterAt interface {
|
||||||
|
io.ReaderAt
|
||||||
|
io.WriterAt
|
||||||
|
}
|
||||||
|
|
||||||
|
type RemoteBackingStore interface {
|
||||||
|
ReaderWriterAt
|
||||||
|
Sync() (int, error)
|
||||||
|
Unmap(int64, int64) (int, error)
|
||||||
|
}
|
||||||
|
|||||||
@@ -20,7 +20,9 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gostor/gotgt/pkg/api"
|
||||||
"github.com/gostor/gotgt/pkg/util"
|
"github.com/gostor/gotgt/pkg/util"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
@@ -93,6 +95,7 @@ type ISCSICommand struct {
|
|||||||
FinalInSeq bool
|
FinalInSeq bool
|
||||||
Immediate bool
|
Immediate bool
|
||||||
TaskTag uint32
|
TaskTag uint32
|
||||||
|
StartTime time.Time
|
||||||
ExpCmdSN, MaxCmdSN uint32
|
ExpCmdSN, MaxCmdSN uint32
|
||||||
AHSLen int
|
AHSLen int
|
||||||
Resid uint32
|
Resid uint32
|
||||||
@@ -124,6 +127,7 @@ type ISCSICommand struct {
|
|||||||
StatusDetail uint8
|
StatusDetail uint8
|
||||||
|
|
||||||
// SCSI commands
|
// SCSI commands
|
||||||
|
SCSIOpCode byte
|
||||||
ExpectedDataLen uint32
|
ExpectedDataLen uint32
|
||||||
CDB []byte
|
CDB []byte
|
||||||
Status byte
|
Status byte
|
||||||
@@ -225,6 +229,7 @@ func parseHeader(data []byte) (*ISCSICommand, error) {
|
|||||||
m.AHSLen = int(data[4]) * 4
|
m.AHSLen = int(data[4]) * 4
|
||||||
m.DataLen = int(ParseUint(data[5:8]))
|
m.DataLen = int(ParseUint(data[5:8]))
|
||||||
m.TaskTag = uint32(ParseUint(data[16:20]))
|
m.TaskTag = uint32(ParseUint(data[16:20]))
|
||||||
|
m.StartTime = time.Now()
|
||||||
switch m.OpCode {
|
switch m.OpCode {
|
||||||
case OpSCSICmd:
|
case OpSCSICmd:
|
||||||
m.LUN = [8]byte{data[9]}
|
m.LUN = [8]byte{data[9]}
|
||||||
@@ -234,6 +239,14 @@ func parseHeader(data []byte) (*ISCSICommand, error) {
|
|||||||
m.Write = data[1]&0x20 == 0x20
|
m.Write = data[1]&0x20 == 0x20
|
||||||
m.CDB = data[32:48]
|
m.CDB = data[32:48]
|
||||||
m.ExpStatSN = uint32(ParseUint(data[28:32]))
|
m.ExpStatSN = uint32(ParseUint(data[28:32]))
|
||||||
|
m.SCSIOpCode = m.CDB[0]
|
||||||
|
SCSIOpcode := api.SCSICommandType(m.SCSIOpCode)
|
||||||
|
switch SCSIOpcode {
|
||||||
|
case api.READ_6, api.READ_10, api.READ_12, api.READ_16:
|
||||||
|
m.Read = true
|
||||||
|
case api.WRITE_6, api.WRITE_10, api.WRITE_12, api.WRITE_16, api.WRITE_VERIFY, api.WRITE_VERIFY_12, api.WRITE_VERIFY_16:
|
||||||
|
m.Write = true
|
||||||
|
}
|
||||||
fallthrough
|
fallthrough
|
||||||
case OpSCSITaskReq:
|
case OpSCSITaskReq:
|
||||||
m.ReferencedTaskTag = uint32(ParseUint(data[20:24]))
|
m.ReferencedTaskTag = uint32(ParseUint(data[20:24]))
|
||||||
@@ -358,7 +371,9 @@ func (m *ISCSICommand) dataInBytes() []byte {
|
|||||||
copy(buf[36:], util.MarshalUint32(m.DataSN))
|
copy(buf[36:], util.MarshalUint32(m.DataSN))
|
||||||
copy(buf[40:], util.MarshalUint32(m.BufferOffset))
|
copy(buf[40:], util.MarshalUint32(m.BufferOffset))
|
||||||
copy(buf[44:], util.MarshalUint32(m.Resid))
|
copy(buf[44:], util.MarshalUint32(m.Resid))
|
||||||
copy(buf[48:], m.RawData[m.BufferOffset:m.BufferOffset+uint32(m.DataLen)])
|
if m.ExpectedDataLen != 0 {
|
||||||
|
copy(buf[48:], m.RawData[m.BufferOffset:m.BufferOffset+uint32(m.DataLen)])
|
||||||
|
}
|
||||||
|
|
||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type iscsiConnection struct {
|
type iscsiConnection struct {
|
||||||
|
ConnNum int
|
||||||
state int
|
state int
|
||||||
authState int
|
authState int
|
||||||
session *ISCSISession
|
session *ISCSISession
|
||||||
@@ -96,12 +97,13 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type iscsiTask struct {
|
type iscsiTask struct {
|
||||||
tag uint32
|
tag uint32
|
||||||
conn *iscsiConnection
|
conn *iscsiConnection
|
||||||
cmd *ISCSICommand
|
cmd *ISCSICommand
|
||||||
scmd *api.SCSICommand
|
scmd *api.SCSICommand
|
||||||
state taskState
|
state taskState
|
||||||
result byte
|
expectedDataLength int64
|
||||||
|
result byte
|
||||||
|
|
||||||
offset int
|
offset int
|
||||||
r2tCount int
|
r2tCount int
|
||||||
@@ -154,6 +156,7 @@ func (conn *iscsiConnection) buildRespPackage(oc OpCode, task *iscsiTask) error
|
|||||||
task = conn.rxTask
|
task = conn.rxTask
|
||||||
}
|
}
|
||||||
conn.resp = &ISCSICommand{
|
conn.resp = &ISCSICommand{
|
||||||
|
StartTime: conn.req.StartTime,
|
||||||
StatSN: conn.req.ExpStatSN,
|
StatSN: conn.req.ExpStatSN,
|
||||||
TaskTag: conn.req.TaskTag,
|
TaskTag: conn.req.TaskTag,
|
||||||
ExpCmdSN: conn.session.ExpCmdSN,
|
ExpCmdSN: conn.session.ExpCmdSN,
|
||||||
@@ -164,6 +167,7 @@ func (conn *iscsiConnection) buildRespPackage(oc OpCode, task *iscsiTask) error
|
|||||||
case OpReady:
|
case OpReady:
|
||||||
conn.resp.OpCode = OpReady
|
conn.resp.OpCode = OpReady
|
||||||
conn.resp.R2TSN = task.r2tSN
|
conn.resp.R2TSN = task.r2tSN
|
||||||
|
conn.resp.Final = true
|
||||||
conn.resp.BufferOffset = uint32(task.offset)
|
conn.resp.BufferOffset = uint32(task.offset)
|
||||||
conn.resp.DesiredLength = uint32(task.r2tCount)
|
conn.resp.DesiredLength = uint32(task.r2tCount)
|
||||||
if val := conn.loginParam.sessionParam[ISCSI_PARAM_MAX_BURST].Value; task.r2tCount > int(val) {
|
if val := conn.loginParam.sessionParam[ISCSI_PARAM_MAX_BURST].Value; task.r2tCount > int(val) {
|
||||||
@@ -171,6 +175,7 @@ func (conn *iscsiConnection) buildRespPackage(oc OpCode, task *iscsiTask) error
|
|||||||
}
|
}
|
||||||
case OpSCSIIn, OpSCSIResp:
|
case OpSCSIIn, OpSCSIResp:
|
||||||
conn.resp.OpCode = oc
|
conn.resp.OpCode = oc
|
||||||
|
conn.resp.SCSIOpCode = conn.req.SCSIOpCode
|
||||||
conn.resp.Immediate = true
|
conn.resp.Immediate = true
|
||||||
conn.resp.Final = true
|
conn.resp.Final = true
|
||||||
conn.resp.SCSIResponse = 0x00
|
conn.resp.SCSIResponse = 0x00
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/gostor/gotgt/pkg/api"
|
"github.com/gostor/gotgt/pkg/api"
|
||||||
"github.com/gostor/gotgt/pkg/config"
|
"github.com/gostor/gotgt/pkg/config"
|
||||||
@@ -35,15 +36,30 @@ const (
|
|||||||
ISCSI_UNSPEC_TSIH = uint16(0)
|
ISCSI_UNSPEC_TSIH = uint16(0)
|
||||||
)
|
)
|
||||||
|
|
||||||
type ISCSITargetDriver struct {
|
const (
|
||||||
SCSI *scsi.SCSITargetService
|
STATE_INIT = iota
|
||||||
Name string
|
STATE_RUNNING
|
||||||
iSCSITargets map[string]*ISCSITarget
|
STATE_SHUTTING_DOWN
|
||||||
TSIHPool map[uint16]bool
|
STATE_TERMINATE
|
||||||
TSIHPoolMutex sync.Mutex
|
)
|
||||||
|
|
||||||
mu sync.Mutex
|
var (
|
||||||
l net.Listener
|
EnableStats bool
|
||||||
|
)
|
||||||
|
|
||||||
|
type ISCSITargetDriver struct {
|
||||||
|
SCSI *scsi.SCSITargetService
|
||||||
|
Name string
|
||||||
|
iSCSITargets map[string]*ISCSITarget
|
||||||
|
TSIHPool map[uint16]bool
|
||||||
|
TSIHPoolMutex sync.Mutex
|
||||||
|
isClientConnected bool
|
||||||
|
enableStats bool
|
||||||
|
mu *sync.RWMutex
|
||||||
|
l net.Listener
|
||||||
|
state uint8
|
||||||
|
OpCode int
|
||||||
|
TargetStats scsi.Stats
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -51,12 +67,19 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewISCSITargetDriver(base *scsi.SCSITargetService) (scsi.SCSITargetDriver, error) {
|
func NewISCSITargetDriver(base *scsi.SCSITargetService) (scsi.SCSITargetDriver, error) {
|
||||||
return &ISCSITargetDriver{
|
driver := &ISCSITargetDriver{
|
||||||
Name: iSCSIDriverName,
|
Name: iSCSIDriverName,
|
||||||
iSCSITargets: map[string]*ISCSITarget{},
|
iSCSITargets: map[string]*ISCSITarget{},
|
||||||
SCSI: base,
|
SCSI: base,
|
||||||
TSIHPool: map[uint16]bool{0: true, 65535: true},
|
TSIHPool: map[uint16]bool{0: true, 65535: true},
|
||||||
}, nil
|
mu: &sync.RWMutex{},
|
||||||
|
}
|
||||||
|
|
||||||
|
if EnableStats {
|
||||||
|
driver.enableStats = true
|
||||||
|
driver.TargetStats.SCSIIOCount = map[int]int64{}
|
||||||
|
}
|
||||||
|
return driver, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ISCSITargetDriver) AllocTSIH() uint16 {
|
func (s *ISCSITargetDriver) AllocTSIH() uint16 {
|
||||||
@@ -165,46 +188,72 @@ func (s *ISCSITargetDriver) Run() error {
|
|||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
s.l = l
|
s.l = l
|
||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
|
log.Infof("iSCSI service listening on: %v", s.l.Addr())
|
||||||
|
|
||||||
|
s.setState(STATE_RUNNING)
|
||||||
for {
|
for {
|
||||||
log.Info("Listening ...")
|
|
||||||
conn, err := l.Accept()
|
conn, err := l.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err, ok := err.(net.Error); ok {
|
if err, ok := err.(net.Error); ok {
|
||||||
if !err.Temporary() {
|
if !err.Temporary() {
|
||||||
log.Info("Closing ...")
|
log.Warning("Closing connection with initiator...")
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info(conn.LocalAddr().String())
|
log.Info(conn.LocalAddr().String())
|
||||||
log.Info("Accepting ...")
|
s.setClientStatus(true)
|
||||||
|
|
||||||
iscsiConn := &iscsiConnection{conn: conn,
|
iscsiConn := &iscsiConnection{conn: conn,
|
||||||
loginParam: &iscsiLoginParam{}}
|
loginParam: &iscsiLoginParam{}}
|
||||||
|
|
||||||
iscsiConn.init()
|
iscsiConn.init()
|
||||||
iscsiConn.rxIOState = IOSTATE_RX_BHS
|
iscsiConn.rxIOState = IOSTATE_RX_BHS
|
||||||
|
log.Infof("Target is connected to initiator: %s", conn.RemoteAddr().String())
|
||||||
log.Infof("connection is connected from %s...\n", conn.RemoteAddr().String())
|
|
||||||
// start a new thread to do with this command
|
// start a new thread to do with this command
|
||||||
go s.handler(DATAIN, iscsiConn)
|
go s.handler(DATAIN, iscsiConn)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *ISCSITargetDriver) setClientStatus(ok bool) {
|
||||||
|
s.isClientConnected = ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ISCSITargetDriver) isInitiatorConnected() bool {
|
||||||
|
return s.isClientConnected
|
||||||
|
}
|
||||||
func (s *ISCSITargetDriver) Close() error {
|
func (s *ISCSITargetDriver) Close() error {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
l := s.l
|
l := s.l
|
||||||
|
s.setClientStatus(false)
|
||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
if l != nil {
|
if l != nil {
|
||||||
return l.Close()
|
s.setState(STATE_SHUTTING_DOWN)
|
||||||
|
if err := l.Close(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.setState(STATE_TERMINATE)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *ISCSITargetDriver) setState(st uint8) {
|
||||||
|
s.mu.Lock()
|
||||||
|
defer s.mu.Unlock()
|
||||||
|
s.state = st
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ISCSITargetDriver) Resize(size uint64) error {
|
||||||
|
s.mu.Lock()
|
||||||
|
defer s.mu.Unlock()
|
||||||
|
return s.SCSI.Resize(size)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *ISCSITargetDriver) handler(events byte, conn *iscsiConnection) {
|
func (s *ISCSITargetDriver) handler(events byte, conn *iscsiConnection) {
|
||||||
|
|
||||||
if events&DATAIN != 0 {
|
if events&DATAIN != 0 {
|
||||||
@@ -324,6 +373,7 @@ func (s *ISCSITargetDriver) rxHandler(conn *iscsiConnection) {
|
|||||||
}
|
}
|
||||||
case OpLogoutReq:
|
case OpLogoutReq:
|
||||||
log.Debug("OpLogoutReq")
|
log.Debug("OpLogoutReq")
|
||||||
|
s.setClientStatus(false)
|
||||||
if err := iscsiExecLogout(conn); err != nil {
|
if err := iscsiExecLogout(conn); err != nil {
|
||||||
log.Warningf("set connection to close")
|
log.Warningf("set connection to close")
|
||||||
conn.state = CONN_STATE_CLOSE
|
conn.state = CONN_STATE_CLOSE
|
||||||
@@ -386,6 +436,7 @@ func (s *ISCSITargetDriver) iscsiExecLogin(conn *iscsiConnection) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func iscsiExecLogout(conn *iscsiConnection) error {
|
func iscsiExecLogout(conn *iscsiConnection) error {
|
||||||
|
log.Infof("Logout request received from initiator: %v", conn.conn.RemoteAddr().String())
|
||||||
cmd := conn.req
|
cmd := conn.req
|
||||||
conn.resp = &ISCSICommand{
|
conn.resp = &ISCSICommand{
|
||||||
OpCode: OpLogoutResp,
|
OpCode: OpLogoutResp,
|
||||||
@@ -473,6 +524,12 @@ func (s *ISCSITargetDriver) txHandler(conn *iscsiConnection) {
|
|||||||
resp.DataSN = 0
|
resp.DataSN = 0
|
||||||
maxCount := conn.maxSeqCount
|
maxCount := conn.maxSeqCount
|
||||||
|
|
||||||
|
if s.enableStats {
|
||||||
|
if resp.OpCode == OpSCSIResp || resp.OpCode == OpSCSIIn {
|
||||||
|
s.UpdateStats(conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* send data splitted by segmentLen */
|
/* send data splitted by segmentLen */
|
||||||
SendRemainingData:
|
SendRemainingData:
|
||||||
if resp.OpCode == OpSCSIIn {
|
if resp.OpCode == OpSCSIIn {
|
||||||
@@ -573,6 +630,13 @@ func (s *ISCSITargetDriver) scsiCommandHandler(conn *iscsiConnection) (err error
|
|||||||
switch req.OpCode {
|
switch req.OpCode {
|
||||||
case OpSCSICmd:
|
case OpSCSICmd:
|
||||||
log.Debugf("SCSI Command processing...")
|
log.Debugf("SCSI Command processing...")
|
||||||
|
if s.enableStats {
|
||||||
|
if _, ok := s.TargetStats.SCSIIOCount[(int)(req.CDB[0])]; ok != false {
|
||||||
|
s.TargetStats.SCSIIOCount[(int)(req.CDB[0])] += 1
|
||||||
|
} else {
|
||||||
|
s.TargetStats.SCSIIOCount[(int)(req.CDB[0])] = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
scmd := &api.SCSICommand{
|
scmd := &api.SCSICommand{
|
||||||
ITNexusID: conn.session.ITNexus.ID,
|
ITNexusID: conn.session.ITNexus.ID,
|
||||||
SCB: req.CDB,
|
SCB: req.CDB,
|
||||||
@@ -594,8 +658,17 @@ func (s *ISCSITargetDriver) scsiCommandHandler(conn *iscsiConnection) (err error
|
|||||||
}
|
}
|
||||||
|
|
||||||
task := &iscsiTask{conn: conn, cmd: conn.req, tag: conn.req.TaskTag, scmd: scmd}
|
task := &iscsiTask{conn: conn, cmd: conn.req, tag: conn.req.TaskTag, scmd: scmd}
|
||||||
|
task.scmd.OpCode = conn.req.SCSIOpCode
|
||||||
|
if scmd.Direction == api.SCSIDataBidirection {
|
||||||
|
task.scmd.Result = api.SAMStatCheckCondition.Stat
|
||||||
|
scsi.BuildSenseData(task.scmd, scsi.ILLEGAL_REQUEST, scsi.NO_ADDITIONAL_SENSE)
|
||||||
|
conn.buildRespPackage(OpSCSIResp, task)
|
||||||
|
conn.rxTask = nil
|
||||||
|
break
|
||||||
|
}
|
||||||
if req.Write {
|
if req.Write {
|
||||||
task.r2tCount = int(req.ExpectedDataLen) - req.DataLen
|
task.r2tCount = int(req.ExpectedDataLen) - req.DataLen
|
||||||
|
task.expectedDataLength = int64(req.ExpectedDataLen)
|
||||||
if !req.Final {
|
if !req.Final {
|
||||||
task.unsolCount = 1
|
task.unsolCount = 1
|
||||||
}
|
}
|
||||||
@@ -649,7 +722,7 @@ func (s *ISCSITargetDriver) scsiCommandHandler(conn *iscsiConnection) (err error
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
if scmd.Direction == api.SCSIDataRead && scmd.SenseBuffer == nil {
|
if scmd.Direction == api.SCSIDataRead && scmd.SenseBuffer == nil && req.ExpectedDataLen != 0 {
|
||||||
conn.buildRespPackage(OpSCSIIn, task)
|
conn.buildRespPackage(OpSCSIIn, task)
|
||||||
} else {
|
} else {
|
||||||
conn.buildRespPackage(OpSCSIResp, task)
|
conn.buildRespPackage(OpSCSIResp, task)
|
||||||
@@ -710,6 +783,7 @@ func (s *ISCSITargetDriver) scsiCommandHandler(conn *iscsiConnection) (err error
|
|||||||
case OpNoopOut:
|
case OpNoopOut:
|
||||||
iscsiExecNoopOut(conn)
|
iscsiExecNoopOut(conn)
|
||||||
case OpLogoutReq:
|
case OpLogoutReq:
|
||||||
|
s.setClientStatus(false)
|
||||||
conn.txTask = &iscsiTask{conn: conn, cmd: conn.req, tag: conn.req.TaskTag}
|
conn.txTask = &iscsiTask{conn: conn, cmd: conn.req, tag: conn.req.TaskTag}
|
||||||
conn.txIOState = IOSTATE_TX_BHS
|
conn.txIOState = IOSTATE_TX_BHS
|
||||||
iscsiExecLogout(conn)
|
iscsiExecLogout(conn)
|
||||||
@@ -824,13 +898,31 @@ func (s *ISCSITargetDriver) iscsiExecTask(task *iscsiTask) error {
|
|||||||
fallthrough
|
fallthrough
|
||||||
case ISCSI_TM_FUNC_TARGET_WARM_RESET, ISCSI_TM_FUNC_TARGET_COLD_RESET, ISCSI_TM_FUNC_TASK_REASSIGN:
|
case ISCSI_TM_FUNC_TARGET_WARM_RESET, ISCSI_TM_FUNC_TARGET_COLD_RESET, ISCSI_TM_FUNC_TASK_REASSIGN:
|
||||||
task.result = ISCSI_TMF_RSP_NOT_SUPPORTED
|
task.result = ISCSI_TMF_RSP_NOT_SUPPORTED
|
||||||
return fmt.Errorf("The task function is not supported")
|
|
||||||
default:
|
default:
|
||||||
task.result = ISCSI_TMF_RSP_REJECTED
|
task.result = ISCSI_TMF_RSP_REJECTED
|
||||||
return fmt.Errorf("Unknown task function")
|
|
||||||
}
|
}
|
||||||
// return response to initiator
|
// return response to initiator
|
||||||
return task.conn.buildRespPackage(OpSCSITaskResp, task)
|
return task.conn.buildRespPackage(OpSCSITaskResp, task)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *ISCSITargetDriver) Stats() scsi.Stats {
|
||||||
|
return s.TargetStats
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ISCSITargetDriver) UpdateStats(conn *iscsiConnection) {
|
||||||
|
s.TargetStats.IsClientConnected = s.isClientConnected
|
||||||
|
switch api.SCSICommandType(conn.resp.SCSIOpCode) {
|
||||||
|
case api.READ_6, api.READ_10, api.READ_12, api.READ_16:
|
||||||
|
s.TargetStats.ReadIOPS += 1
|
||||||
|
s.TargetStats.TotalReadTime += int64(time.Since(conn.resp.StartTime))
|
||||||
|
s.TargetStats.TotalReadBlockCount += int64(conn.resp.ExpectedDataLen)
|
||||||
|
break
|
||||||
|
case api.WRITE_6, api.WRITE_10, api.WRITE_12, api.WRITE_16:
|
||||||
|
s.TargetStats.WriteIOPS += 1
|
||||||
|
s.TargetStats.TotalWriteTime += int64(time.Since(conn.resp.StartTime))
|
||||||
|
s.TargetStats.TotalWriteBlockCount += int64(conn.resp.ExpectedDataLen)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -152,8 +152,8 @@ func (conn *iscsiConnection) processLoginData() ([]util.KeyValue, error) {
|
|||||||
conn.loginParam.iniCSG, conn.loginParam.iniNSG, conn.loginParam.iniTrans)
|
conn.loginParam.iniCSG, conn.loginParam.iniNSG, conn.loginParam.iniTrans)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
conn.loginParam.tgtNSG = LoginOperationalNegotiation
|
conn.loginParam.tgtNSG = FullFeaturePhase
|
||||||
conn.loginParam.tgtTrans = false
|
conn.loginParam.tgtTrans = true
|
||||||
}
|
}
|
||||||
return negoKV, nil
|
return negoKV, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,13 +184,13 @@ func boolKeyInConv(value uint) string {
|
|||||||
|
|
||||||
var sessionKeys map[string]*iscsiSessionKeys = map[string]*iscsiSessionKeys{
|
var sessionKeys map[string]*iscsiSessionKeys = map[string]*iscsiSessionKeys{
|
||||||
// ISCSI_PARAM_MAX_RECV_DLENGTH
|
// ISCSI_PARAM_MAX_RECV_DLENGTH
|
||||||
"MaxRecvDataSegmentLength": {ISCSI_PARAM_MAX_RECV_DLENGTH, true, 32768, 512, 16777215, numberKeyConv, numberKeyInConv},
|
"MaxRecvDataSegmentLength": {ISCSI_PARAM_MAX_RECV_DLENGTH, true, 65536, 512, 16777215, numberKeyConv, numberKeyInConv},
|
||||||
// ISCSI_PARAM_HDRDGST_EN
|
// ISCSI_PARAM_HDRDGST_EN
|
||||||
"HeaderDigest": {ISCSI_PARAM_HDRDGST_EN, false, DIGEST_NONE, DIGEST_NONE, DIGEST_ALL, digestKeyConv, digestKeyInConv},
|
"HeaderDigest": {ISCSI_PARAM_HDRDGST_EN, false, DIGEST_NONE, DIGEST_NONE, DIGEST_ALL, digestKeyConv, digestKeyInConv},
|
||||||
// ISCSI_PARAM_DATADGST_EN
|
// ISCSI_PARAM_DATADGST_EN
|
||||||
"DataDigest": {ISCSI_PARAM_DATADGST_EN, false, DIGEST_NONE, DIGEST_NONE, DIGEST_ALL, digestKeyConv, digestKeyInConv},
|
"DataDigest": {ISCSI_PARAM_DATADGST_EN, false, DIGEST_NONE, DIGEST_NONE, DIGEST_ALL, digestKeyConv, digestKeyInConv},
|
||||||
// ISCSI_PARAM_INITIAL_R2T_EN
|
// ISCSI_PARAM_INITIAL_R2T_EN
|
||||||
"InitialR2T": {ISCSI_PARAM_INITIAL_R2T_EN, false, 1, 0, 1, boolKeyConv, boolKeyInConv},
|
"InitialR2T": {ISCSI_PARAM_INITIAL_R2T_EN, true, 1, 0, 1, boolKeyConv, boolKeyInConv},
|
||||||
// ISCSI_PARAM_MAX_R2T
|
// ISCSI_PARAM_MAX_R2T
|
||||||
"MaxOutstandingR2T": {ISCSI_PARAM_MAX_R2T, true, 1, 1, 65535, numberKeyConv, numberKeyInConv},
|
"MaxOutstandingR2T": {ISCSI_PARAM_MAX_R2T, true, 1, 1, 65535, numberKeyConv, numberKeyInConv},
|
||||||
// ISCSI_PARAM_IMM_DATA_EN
|
// ISCSI_PARAM_IMM_DATA_EN
|
||||||
@@ -392,8 +392,8 @@ func (s *ISCSITargetDriver) BindISCSISession(conn *iscsiConnection) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if newSess.SessionType == SESSION_NORMAL {
|
if newSess.SessionType == SESSION_NORMAL {
|
||||||
log.Infof("New Session initiator name:%v,target name:%v,ISID:0x%x",
|
log.Infof("Login request received from initiator: %v, Session type: %s, Target name:%v, ISID: 0x%x",
|
||||||
conn.loginParam.initiator, conn.loginParam.target, conn.loginParam.isid)
|
conn.loginParam.initiator, "Normal", conn.loginParam.target, conn.loginParam.isid)
|
||||||
//register normal session
|
//register normal session
|
||||||
itnexus := &api.ITNexus{uuid.NewV1(), GeniSCSIITNexusID(newSess)}
|
itnexus := &api.ITNexus{uuid.NewV1(), GeniSCSIITNexusID(newSess)}
|
||||||
scsi.AddITNexus(&newSess.Target.SCSITarget, itnexus)
|
scsi.AddITNexus(&newSess.Target.SCSITarget, itnexus)
|
||||||
@@ -404,6 +404,8 @@ func (s *ISCSITargetDriver) BindISCSISession(conn *iscsiConnection) error {
|
|||||||
newSess.Target.Sessions[newSess.TSIH] = newSess
|
newSess.Target.Sessions[newSess.TSIH] = newSess
|
||||||
newSess.Target.SessionsRWMutex.Unlock()
|
newSess.Target.SessionsRWMutex.Unlock()
|
||||||
} else {
|
} else {
|
||||||
|
log.Infof("Discovery request received from initiator: %v, Session type: %s, ISID: 0x%x",
|
||||||
|
conn.loginParam.initiator, "Discovery", conn.loginParam.isid)
|
||||||
conn.session = newSess
|
conn.session = newSess
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -125,6 +125,11 @@ func bsPerformCommand(bs api.BackingStore, cmd *api.SCSICommand) (err error, key
|
|||||||
bs.DataAdvise(int64(offset), int64(length), util.POSIX_FADV_NOREUSE)
|
bs.DataAdvise(int64(offset), int64(length), util.POSIX_FADV_NOREUSE)
|
||||||
}
|
}
|
||||||
cmd.InSDBBuffer.Resid = uint32(length)
|
cmd.InSDBBuffer.Resid = uint32(length)
|
||||||
|
if cmd.InSDBBuffer.Length < uint32(length) {
|
||||||
|
key = ILLEGAL_REQUEST
|
||||||
|
asc = ASC_INVALID_FIELD_IN_CDB
|
||||||
|
goto sense
|
||||||
|
}
|
||||||
copy(cmd.InSDBBuffer.Buffer, rbuf)
|
copy(cmd.InSDBBuffer.Buffer, rbuf)
|
||||||
case api.PRE_FETCH_10, api.PRE_FETCH_16:
|
case api.PRE_FETCH_10, api.PRE_FETCH_16:
|
||||||
err = bs.DataAdvise(int64(offset), tl, util.POSIX_FADV_WILLNEED)
|
err = bs.DataAdvise(int64(offset), tl, util.POSIX_FADV_WILLNEED)
|
||||||
@@ -148,7 +153,7 @@ write:
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
key = MEDIUM_ERROR
|
key = MEDIUM_ERROR
|
||||||
asc = ASC_READ_ERROR
|
asc = ASC_WRITE_ERROR
|
||||||
goto sense
|
goto sense
|
||||||
}
|
}
|
||||||
log.Debugf("write data at 0x%x for length %d", offset, len(wbuf))
|
log.Debugf("write data at 0x%x for length %d", offset, len(wbuf))
|
||||||
@@ -167,7 +172,7 @@ write:
|
|||||||
if ((opcode != api.WRITE_6) && (scb[1]&0x8 != 0)) || (pg.Data[0]&0x04 == 0) {
|
if ((opcode != api.WRITE_6) && (scb[1]&0x8 != 0)) || (pg.Data[0]&0x04 == 0) {
|
||||||
if err = bs.DataSync(int64(offset), tl); err != nil {
|
if err = bs.DataSync(int64(offset), tl); err != nil {
|
||||||
key = MEDIUM_ERROR
|
key = MEDIUM_ERROR
|
||||||
asc = ASC_READ_ERROR
|
asc = ASC_WRITE_ERROR
|
||||||
goto sense
|
goto sense
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
118
pkg/scsi/backingstore/remote/remote.go
Normal file
118
pkg/scsi/backingstore/remote/remote.go
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 openebs 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 remote
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/gostor/gotgt/pkg/api"
|
||||||
|
"github.com/gostor/gotgt/pkg/scsi"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
Size uint64
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
scsi.RegisterBackingStore("RemBs", NewRemoteBackingStore)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemBackingStore
|
||||||
|
type RemBackingStore struct {
|
||||||
|
scsi.BaseBackingStore
|
||||||
|
// Remote backing store, remote server exposing
|
||||||
|
// read and write methods.
|
||||||
|
RemBs api.RemoteBackingStore
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRemoteBackingStore() (api.BackingStore, error) {
|
||||||
|
return &RemBackingStore{
|
||||||
|
BaseBackingStore: scsi.BaseBackingStore{
|
||||||
|
Name: "RemBs",
|
||||||
|
OflagsSupported: 0,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bs *RemBackingStore) Open(dev *api.SCSILu, path string) error {
|
||||||
|
if Size == 0 {
|
||||||
|
return fmt.Errorf("Size is not initialized")
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
bs.DataSize = Size
|
||||||
|
bs.RemBs, err = scsi.GetTargetBSMap(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bs *RemBackingStore) Close(dev *api.SCSILu) error {
|
||||||
|
/* TODO return bs.File.Close()*/
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bs *RemBackingStore) Init(dev *api.SCSILu, Opts string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bs *RemBackingStore) Exit(dev *api.SCSILu) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bs *RemBackingStore) Size(dev *api.SCSILu) uint64 {
|
||||||
|
return bs.DataSize
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bs *RemBackingStore) Read(offset, tl int64) ([]byte, error) {
|
||||||
|
tmpbuf := make([]byte, tl)
|
||||||
|
length, err := bs.RemBs.ReadAt(tmpbuf, offset)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if length != len(tmpbuf) {
|
||||||
|
return nil, fmt.Errorf("Incomplete read expected:%d actual:%d", tl, length)
|
||||||
|
}
|
||||||
|
return tmpbuf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bs *RemBackingStore) Write(wbuf []byte, offset int64) error {
|
||||||
|
length, err := bs.RemBs.WriteAt(wbuf, offset)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if length != len(wbuf) {
|
||||||
|
return fmt.Errorf("Incomplete write expected:%d actual:%d", len(wbuf), length)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bs *RemBackingStore) DataAdvise(offset, length int64, advise uint32) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bs *RemBackingStore) DataSync(offset, length int64) (err error) {
|
||||||
|
_, err = bs.RemBs.Sync()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bs *RemBackingStore) Unmap(bd []api.UnmapBlockDescriptor) (err error) {
|
||||||
|
//_, err = bs.RemBs.Unmap(int64(bd[0].Offset), int64(bd[0].TL))
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -228,9 +228,10 @@ const (
|
|||||||
NAA_IEEE_REGD_EXTD = byte(0x6)
|
NAA_IEEE_REGD_EXTD = byte(0x6)
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
var (
|
||||||
SCSIVendorID = "GOSTOR"
|
SCSIVendorID = "GOSTOR"
|
||||||
SCSIProductID = "GOTGT"
|
SCSIProductID = "GOTGT"
|
||||||
|
SCSIID = "iqn.2016-09.com.gotgt.gostor:iscsi-tgt"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -28,6 +28,27 @@ type SCSITargetDriver interface {
|
|||||||
NewTarget(string, *config.Config) error
|
NewTarget(string, *config.Config) error
|
||||||
RereadTargetLUNMap()
|
RereadTargetLUNMap()
|
||||||
Close() error
|
Close() error
|
||||||
|
Resize(uint64) error
|
||||||
|
Stats() Stats
|
||||||
|
}
|
||||||
|
|
||||||
|
type Stats struct {
|
||||||
|
IsClientConnected bool
|
||||||
|
RevisionCounter int64
|
||||||
|
ReplicaCounter int64
|
||||||
|
SCSIIOCount map[int]int64
|
||||||
|
|
||||||
|
ReadIOPS int64
|
||||||
|
TotalReadTime int64
|
||||||
|
TotalReadBlockCount int64
|
||||||
|
|
||||||
|
WriteIOPS int64
|
||||||
|
TotalWriteTime int64
|
||||||
|
TotalWriteBlockCount int64
|
||||||
|
|
||||||
|
UsedLogicalBlocks int64
|
||||||
|
UsedBlocks int64
|
||||||
|
SectorSize int64
|
||||||
}
|
}
|
||||||
|
|
||||||
type TargetDriverFunc func(*SCSITargetService) (SCSITargetDriver, error)
|
type TargetDriverFunc func(*SCSITargetService) (SCSITargetDriver, error)
|
||||||
|
|||||||
@@ -37,6 +37,11 @@ const (
|
|||||||
PR_EA_FN = (1 << 0)
|
PR_EA_FN = (1 << 0)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
EnableORWrite16 = true
|
||||||
|
EnablePersistentReservation = true
|
||||||
|
)
|
||||||
|
|
||||||
type SBCSCSIDeviceProtocol struct {
|
type SBCSCSIDeviceProtocol struct {
|
||||||
BaseSCSIDeviceProtocol
|
BaseSCSIDeviceProtocol
|
||||||
}
|
}
|
||||||
@@ -76,7 +81,7 @@ func (sbc SBCSCSIDeviceProtocol) InitLu(lu *api.SCSILu) error {
|
|||||||
leave it with a default target name
|
leave it with a default target name
|
||||||
*/
|
*/
|
||||||
|
|
||||||
lu.Attrs.SCSIID = "iqn.2016-09.com.gotgt.gostor:iscsi-tgt"
|
lu.Attrs.SCSIID = SCSIID
|
||||||
/*
|
/*
|
||||||
The PRODUCT SERIAL NUMBER field contains
|
The PRODUCT SERIAL NUMBER field contains
|
||||||
right-aligned ASCII data (see 4.3.1)
|
right-aligned ASCII data (see 4.3.1)
|
||||||
@@ -176,26 +181,29 @@ func NewSBCDevice(deviceType api.SCSIDeviceType) api.SCSIDeviceProtocol {
|
|||||||
sbc.SCSIDeviceOps[api.MODE_SELECT_10] = NewSCSIDeviceOperation(SBCModeSelect, nil, PR_WE_FA|PR_EA_FA|PR_EA_FN|PR_WE_FN)
|
sbc.SCSIDeviceOps[api.MODE_SELECT_10] = NewSCSIDeviceOperation(SBCModeSelect, nil, PR_WE_FA|PR_EA_FA|PR_EA_FN|PR_WE_FN)
|
||||||
sbc.SCSIDeviceOps[api.MODE_SENSE_10] = NewSCSIDeviceOperation(SBCModeSense, nil, PR_WE_FA|PR_WE_FN|PR_EA_FA|PR_EA_FN)
|
sbc.SCSIDeviceOps[api.MODE_SENSE_10] = NewSCSIDeviceOperation(SBCModeSense, nil, PR_WE_FA|PR_WE_FN|PR_EA_FA|PR_EA_FN)
|
||||||
|
|
||||||
sbc.SCSIDeviceOps[api.PERSISTENT_RESERVE_IN] = NewSCSIDeviceOperation(SPCServiceAction, []*SCSIServiceAction{
|
if EnablePersistentReservation {
|
||||||
{ServiceAction: PR_IN_READ_KEYS, CommandPerformFunc: SPCPRReadKeys},
|
sbc.SCSIDeviceOps[api.PERSISTENT_RESERVE_IN] = NewSCSIDeviceOperation(SPCServiceAction, []*SCSIServiceAction{
|
||||||
{ServiceAction: PR_IN_READ_RESERVATION, CommandPerformFunc: SPCPRReadReservation},
|
{ServiceAction: PR_IN_READ_KEYS, CommandPerformFunc: SPCPRReadKeys},
|
||||||
{ServiceAction: PR_IN_REPORT_CAPABILITIES, CommandPerformFunc: SPCPRReportCapabilities},
|
{ServiceAction: PR_IN_READ_RESERVATION, CommandPerformFunc: SPCPRReadReservation},
|
||||||
}, 0)
|
{ServiceAction: PR_IN_REPORT_CAPABILITIES, CommandPerformFunc: SPCPRReportCapabilities},
|
||||||
|
}, 0)
|
||||||
sbc.SCSIDeviceOps[api.PERSISTENT_RESERVE_OUT] = NewSCSIDeviceOperation(SPCServiceAction, []*SCSIServiceAction{
|
|
||||||
{ServiceAction: PR_OUT_REGISTER, CommandPerformFunc: SPCPRRegister},
|
|
||||||
{ServiceAction: PR_OUT_RESERVE, CommandPerformFunc: SPCPRReserve},
|
|
||||||
{ServiceAction: PR_OUT_RELEASE, CommandPerformFunc: SPCPRRelease},
|
|
||||||
{ServiceAction: PR_OUT_CLEAR, CommandPerformFunc: SPCPRClear},
|
|
||||||
{ServiceAction: PR_OUT_PREEMPT, CommandPerformFunc: SPCPRPreempt},
|
|
||||||
// {ServiceAction: PR_OUT_PREEMPT_AND_ABORT, CommandPerformFunc: SPCPRPreempt},
|
|
||||||
{ServiceAction: PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY, CommandPerformFunc: SPCPRRegister},
|
|
||||||
{ServiceAction: PR_OUT_REGISTER_AND_MOVE, CommandPerformFunc: SPCPRRegisterAndMove},
|
|
||||||
}, 0)
|
|
||||||
|
|
||||||
|
sbc.SCSIDeviceOps[api.PERSISTENT_RESERVE_OUT] = NewSCSIDeviceOperation(SPCServiceAction, []*SCSIServiceAction{
|
||||||
|
{ServiceAction: PR_OUT_REGISTER, CommandPerformFunc: SPCPRRegister},
|
||||||
|
{ServiceAction: PR_OUT_RESERVE, CommandPerformFunc: SPCPRReserve},
|
||||||
|
{ServiceAction: PR_OUT_RELEASE, CommandPerformFunc: SPCPRRelease},
|
||||||
|
{ServiceAction: PR_OUT_CLEAR, CommandPerformFunc: SPCPRClear},
|
||||||
|
{ServiceAction: PR_OUT_PREEMPT, CommandPerformFunc: SPCPRPreempt},
|
||||||
|
// {ServiceAction: PR_OUT_PREEMPT_AND_ABORT, CommandPerformFunc: SPCPRPreempt},
|
||||||
|
{ServiceAction: PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY, CommandPerformFunc: SPCPRRegister},
|
||||||
|
{ServiceAction: PR_OUT_REGISTER_AND_MOVE, CommandPerformFunc: SPCPRRegisterAndMove},
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
sbc.SCSIDeviceOps[api.READ_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN)
|
sbc.SCSIDeviceOps[api.READ_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN)
|
||||||
sbc.SCSIDeviceOps[api.WRITE_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN|PR_WE_FA|PR_WE_FN)
|
sbc.SCSIDeviceOps[api.WRITE_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN|PR_WE_FA|PR_WE_FN)
|
||||||
sbc.SCSIDeviceOps[api.ORWRITE_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN)
|
if EnableORWrite16 {
|
||||||
|
sbc.SCSIDeviceOps[api.ORWRITE_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN)
|
||||||
|
}
|
||||||
sbc.SCSIDeviceOps[api.WRITE_VERIFY_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN)
|
sbc.SCSIDeviceOps[api.WRITE_VERIFY_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN)
|
||||||
sbc.SCSIDeviceOps[api.VERIFY_16] = NewSCSIDeviceOperation(SBCVerify, nil, PR_EA_FA|PR_EA_FN)
|
sbc.SCSIDeviceOps[api.VERIFY_16] = NewSCSIDeviceOperation(SBCVerify, nil, PR_EA_FA|PR_EA_FN)
|
||||||
|
|
||||||
@@ -459,7 +467,9 @@ func SBCReadWrite(host int, cmd *api.SCSICommand) api.SAMStat {
|
|||||||
|
|
||||||
err, key, asc = bsPerformCommand(dev.Storage, cmd)
|
err, key, asc = bsPerformCommand(dev.Storage, cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
goto sense
|
log.Errorf("Error from backend: %v", err)
|
||||||
|
BuildSenseData(cmd, key, asc)
|
||||||
|
return api.SAMStatBusy
|
||||||
} else {
|
} else {
|
||||||
return api.SAMStatGood
|
return api.SAMStatGood
|
||||||
}
|
}
|
||||||
@@ -533,7 +543,9 @@ overflow:
|
|||||||
cmd.InSDBBuffer.Resid = 8
|
cmd.InSDBBuffer.Resid = 8
|
||||||
return api.SAMStatGood
|
return api.SAMStatGood
|
||||||
sense:
|
sense:
|
||||||
cmd.InSDBBuffer.Resid = 0
|
if cmd.InSDBBuffer != nil {
|
||||||
|
cmd.InSDBBuffer.Resid = 0
|
||||||
|
}
|
||||||
BuildSenseData(cmd, key, asc)
|
BuildSenseData(cmd, key, asc)
|
||||||
return api.SAMStatCheckCondition
|
return api.SAMStatCheckCondition
|
||||||
}
|
}
|
||||||
@@ -679,7 +691,9 @@ func SBCGetLbaStatus(host int, cmd *api.SCSICommand) api.SAMStat {
|
|||||||
}
|
}
|
||||||
return api.SAMStatGood
|
return api.SAMStatGood
|
||||||
sense:
|
sense:
|
||||||
cmd.InSDBBuffer.Resid = 0
|
if cmd.InSDBBuffer != nil {
|
||||||
|
cmd.InSDBBuffer.Resid = 0
|
||||||
|
}
|
||||||
BuildSenseData(cmd, key, asc)
|
BuildSenseData(cmd, key, asc)
|
||||||
return api.SAMStatCheckCondition
|
return api.SAMStatCheckCondition
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,20 @@ func (s *SCSITargetService) GetTargetList() ([]api.SCSITarget, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *SCSITargetService) Resize(size uint64) error {
|
||||||
|
s.mutex.Lock()
|
||||||
|
//TODO for multiple LUNs
|
||||||
|
for _, t := range s.Targets {
|
||||||
|
if t.Devices != nil {
|
||||||
|
for i := range t.Devices {
|
||||||
|
t.Devices[i].Size = size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.mutex.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *SCSITargetService) AddCommandQueue(tid int, scmd *api.SCSICommand) error {
|
func (s *SCSITargetService) AddCommandQueue(tid int, scmd *api.SCSICommand) error {
|
||||||
var (
|
var (
|
||||||
target *api.SCSITarget
|
target *api.SCSITarget
|
||||||
@@ -96,7 +110,7 @@ func (s *SCSITargetService) AddCommandQueue(tid int, scmd *api.SCSICommand) erro
|
|||||||
result := scmd.Device.PerformCommand(tid, scmd)
|
result := scmd.Device.PerformCommand(tid, scmd)
|
||||||
if result != api.SAMStatGood {
|
if result != api.SAMStatGood {
|
||||||
scmd.Result = result.Stat
|
scmd.Result = result.Stat
|
||||||
log.Warnf("%v", result.Err)
|
log.Warnf("opcode: %xh err: %v", scmd.OpCode, result.Err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -128,9 +142,18 @@ func NewSCSIDeviceOperation(fn api.CommandFunc, sa []*SCSIServiceAction, pr uint
|
|||||||
func BuildSenseData(cmd *api.SCSICommand, key byte, asc SCSISubError) {
|
func BuildSenseData(cmd *api.SCSICommand, key byte, asc SCSISubError) {
|
||||||
senseBuffer := &bytes.Buffer{}
|
senseBuffer := &bytes.Buffer{}
|
||||||
inBufLen, ok := SCSICDBBufXLength(cmd.SCB)
|
inBufLen, ok := SCSICDBBufXLength(cmd.SCB)
|
||||||
var length uint32 = 0xa
|
var (
|
||||||
|
length uint32 = 0xa
|
||||||
|
fixedFormat bool = true
|
||||||
|
)
|
||||||
|
|
||||||
if cmd.Device.Attrs.SenseFormat {
|
if cmd.Device != nil {
|
||||||
|
if cmd.Device.Attrs.SenseFormat {
|
||||||
|
fixedFormat = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !fixedFormat {
|
||||||
// descriptor format
|
// descriptor format
|
||||||
// current, not deferred
|
// current, not deferred
|
||||||
senseBuffer.WriteByte(0x72)
|
senseBuffer.WriteByte(0x72)
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package scsi
|
package scsi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -33,9 +34,15 @@ type SCSILUMap struct {
|
|||||||
AllDevices api.LUNMap
|
AllDevices api.LUNMap
|
||||||
// use target name as the key for target's LUN map
|
// use target name as the key for target's LUN map
|
||||||
TargetsLUNMap map[string]api.LUNMap
|
TargetsLUNMap map[string]api.LUNMap
|
||||||
|
|
||||||
|
TargetsBSMap map[string]api.RemoteBackingStore /* use target name as the key for target's Backing Store (temp) */
|
||||||
}
|
}
|
||||||
|
|
||||||
var globalSCSILUMap = SCSILUMap{AllDevices: make(api.LUNMap), TargetsLUNMap: make(map[string]api.LUNMap)}
|
var globalSCSILUMap = SCSILUMap{
|
||||||
|
AllDevices: make(api.LUNMap),
|
||||||
|
TargetsLUNMap: make(map[string]api.LUNMap),
|
||||||
|
TargetsBSMap: make(map[string]api.RemoteBackingStore),
|
||||||
|
}
|
||||||
|
|
||||||
type LUNMapping struct {
|
type LUNMapping struct {
|
||||||
TargetName string
|
TargetName string
|
||||||
@@ -71,6 +78,18 @@ func GetTargetLUNMap(tgtName string) api.LUNMap {
|
|||||||
return lunMap
|
return lunMap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetTargetBSMap(tgtName string) (api.RemoteBackingStore, error) {
|
||||||
|
globalSCSILUMap.mutex.RLock()
|
||||||
|
defer globalSCSILUMap.mutex.RUnlock()
|
||||||
|
|
||||||
|
bs, ok := globalSCSILUMap.TargetsBSMap[tgtName]
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("Remote backing store is not found in globalSCSILUMap")
|
||||||
|
}
|
||||||
|
|
||||||
|
return bs, nil
|
||||||
|
}
|
||||||
|
|
||||||
func AddBackendStorage(bs config.BackendStorage) error {
|
func AddBackendStorage(bs config.BackendStorage) error {
|
||||||
globalSCSILUMap.mutex.Lock()
|
globalSCSILUMap.mutex.Lock()
|
||||||
defer globalSCSILUMap.mutex.Unlock()
|
defer globalSCSILUMap.mutex.Unlock()
|
||||||
@@ -130,3 +149,30 @@ func InitSCSILUMap(config *config.Config) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func InitSCSILUMapEx(config *config.BackendStorage, tgtName string, lun uint64, bs api.RemoteBackingStore) error {
|
||||||
|
if bs == nil {
|
||||||
|
return errors.New("Remote backing store is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
globalSCSILUMap.mutex.Lock()
|
||||||
|
globalSCSILUMap.TargetsBSMap[tgtName] = bs
|
||||||
|
globalSCSILUMap.mutex.Unlock()
|
||||||
|
|
||||||
|
lu, err := NewSCSILu(config)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Init SCSI LU map error, err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
globalSCSILUMap.mutex.Lock()
|
||||||
|
globalSCSILUMap.AllDevices[config.DeviceID] = lu
|
||||||
|
globalSCSILUMap.mutex.Unlock()
|
||||||
|
|
||||||
|
mappingLUN(LUNMapping{
|
||||||
|
DeviceID: config.DeviceID,
|
||||||
|
LUN: lun,
|
||||||
|
TargetName: tgtName,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -28,8 +28,12 @@ import (
|
|||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
EnableMultipath = true
|
||||||
|
)
|
||||||
|
|
||||||
func SPCIllegalOp(host int, cmd *api.SCSICommand) api.SAMStat {
|
func SPCIllegalOp(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||||
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
|
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_OP_CODE)
|
||||||
return api.SAMStatCheckCondition
|
return api.SAMStatCheckCondition
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,7 +329,11 @@ func SPCInquiry(host int, cmd *api.SCSICommand) api.SAMStat {
|
|||||||
}
|
}
|
||||||
//byte 5
|
//byte 5
|
||||||
//SCCS(0) AAC(0) TPGS(0) 3PC(0) PROTECT(0)
|
//SCCS(0) AAC(0) TPGS(0) 3PC(0) PROTECT(0)
|
||||||
addBuf.WriteByte(INQUIRY_TPGS_IMPLICIT)
|
if EnableMultipath {
|
||||||
|
addBuf.WriteByte(INQUIRY_TPGS_IMPLICIT)
|
||||||
|
} else {
|
||||||
|
addBuf.WriteByte(INQUIRY_TPGS_NO)
|
||||||
|
}
|
||||||
//byte 6
|
//byte 6
|
||||||
//ENCSERV(0) VS(0) MULTIP(0) ADDR16(0)
|
//ENCSERV(0) VS(0) MULTIP(0) ADDR16(0)
|
||||||
addBuf.WriteByte(0x00)
|
addBuf.WriteByte(0x00)
|
||||||
@@ -454,7 +462,9 @@ func SPCReportLuns(host int, cmd *api.SCSICommand) api.SAMStat {
|
|||||||
copy(cmd.InSDBBuffer.Buffer, buf.Bytes())
|
copy(cmd.InSDBBuffer.Buffer, buf.Bytes())
|
||||||
return api.SAMStatGood
|
return api.SAMStatGood
|
||||||
sense:
|
sense:
|
||||||
cmd.InSDBBuffer.Resid = 0
|
if cmd.InSDBBuffer != nil {
|
||||||
|
cmd.InSDBBuffer.Resid = 0
|
||||||
|
}
|
||||||
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
|
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
|
||||||
return api.SAMStatCheckCondition
|
return api.SAMStatCheckCondition
|
||||||
}
|
}
|
||||||
@@ -467,7 +477,9 @@ func SPCStartStop(host int, cmd *api.SCSICommand) api.SAMStat {
|
|||||||
return api.SAMStatReservationConflict
|
return api.SAMStatReservationConflict
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.InSDBBuffer.Resid = 0
|
if cmd.InSDBBuffer != nil {
|
||||||
|
cmd.InSDBBuffer.Resid = 0
|
||||||
|
}
|
||||||
scb := cmd.SCB
|
scb := cmd.SCB
|
||||||
pwrcnd = scb[4] & 0xf0
|
pwrcnd = scb[4] & 0xf0
|
||||||
if pwrcnd != 0 {
|
if pwrcnd != 0 {
|
||||||
@@ -662,7 +674,9 @@ func SPCSendDiagnostics(host int, cmd *api.SCSICommand) api.SAMStat {
|
|||||||
|
|
||||||
return api.SAMStatGood
|
return api.SAMStatGood
|
||||||
sense:
|
sense:
|
||||||
cmd.InSDBBuffer.Resid = 0
|
if cmd.InSDBBuffer != nil {
|
||||||
|
cmd.InSDBBuffer.Resid = 0
|
||||||
|
}
|
||||||
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
|
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
|
||||||
return api.SAMStatCheckCondition
|
return api.SAMStatCheckCondition
|
||||||
}
|
}
|
||||||
@@ -711,7 +725,7 @@ func reportOpcodesAll(cmd *api.SCSICommand, rctd int) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func reportOpcodeOne(cmd *api.SCSICommand, rctd int, opcode byte, rsa uint16, serviceAction bool) error {
|
func reportOpcodeOne(cmd *api.SCSICommand, rctd int, opcode byte, rsa uint16, serviceAction bool) error {
|
||||||
return fmt.Errorf("non support")
|
return fmt.Errorf("rsa: %xh, sa:%v not supported", rsa, serviceAction)
|
||||||
}
|
}
|
||||||
|
|
||||||
func SPCReportSupportedOperationCodes(host int, cmd *api.SCSICommand) api.SAMStat {
|
func SPCReportSupportedOperationCodes(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||||
@@ -748,7 +762,9 @@ func SPCReportSupportedOperationCodes(host int, cmd *api.SCSICommand) api.SAMSta
|
|||||||
return api.SAMStatGood
|
return api.SAMStatGood
|
||||||
|
|
||||||
sense:
|
sense:
|
||||||
cmd.InSDBBuffer.Resid = 0
|
if cmd.InSDBBuffer != nil {
|
||||||
|
cmd.InSDBBuffer.Resid = 0
|
||||||
|
}
|
||||||
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
|
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
|
||||||
return api.SAMStatCheckCondition
|
return api.SAMStatCheckCondition
|
||||||
}
|
}
|
||||||
@@ -764,7 +780,9 @@ func SPCServiceAction(host int, cmd *api.SCSICommand) api.SAMStat {
|
|||||||
fnop := serviceAction.(*SCSIServiceAction)
|
fnop := serviceAction.(*SCSIServiceAction)
|
||||||
return fnop.CommandPerformFunc(host, cmd)
|
return fnop.CommandPerformFunc(host, cmd)
|
||||||
}
|
}
|
||||||
cmd.InSDBBuffer.Resid = 0
|
if cmd.InSDBBuffer != nil {
|
||||||
|
cmd.InSDBBuffer.Resid = 0
|
||||||
|
}
|
||||||
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
|
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
|
||||||
return api.SAMStatCheckCondition
|
return api.SAMStatCheckCondition
|
||||||
}
|
}
|
||||||
@@ -797,7 +815,9 @@ func SPCPRReadKeys(host int, cmd *api.SCSICommand) api.SAMStat {
|
|||||||
cmd.InSDBBuffer.Resid = uint32(additionLength)
|
cmd.InSDBBuffer.Resid = uint32(additionLength)
|
||||||
return api.SAMStatGood
|
return api.SAMStatGood
|
||||||
sense:
|
sense:
|
||||||
cmd.InSDBBuffer.Resid = 0
|
if cmd.InSDBBuffer != nil {
|
||||||
|
cmd.InSDBBuffer.Resid = 0
|
||||||
|
}
|
||||||
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
|
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
|
||||||
return api.SAMStatCheckCondition
|
return api.SAMStatCheckCondition
|
||||||
}
|
}
|
||||||
@@ -853,7 +873,9 @@ func SPCPRReadReservation(host int, cmd *api.SCSICommand) api.SAMStat {
|
|||||||
return api.SAMStatGood
|
return api.SAMStatGood
|
||||||
|
|
||||||
sense:
|
sense:
|
||||||
cmd.InSDBBuffer.Resid = 0
|
if cmd.InSDBBuffer != nil {
|
||||||
|
cmd.InSDBBuffer.Resid = 0
|
||||||
|
}
|
||||||
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
|
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
|
||||||
return api.SAMStatCheckCondition
|
return api.SAMStatCheckCondition
|
||||||
}
|
}
|
||||||
@@ -891,7 +913,9 @@ func SPCPRReportCapabilities(host int, cmd *api.SCSICommand) api.SAMStat {
|
|||||||
cmd.InSDBBuffer.Resid = uint32(actualLength)
|
cmd.InSDBBuffer.Resid = uint32(actualLength)
|
||||||
return api.SAMStatGood
|
return api.SAMStatGood
|
||||||
sense:
|
sense:
|
||||||
cmd.InSDBBuffer.Resid = 0
|
if cmd.InSDBBuffer != nil {
|
||||||
|
cmd.InSDBBuffer.Resid = 0
|
||||||
|
}
|
||||||
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
|
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
|
||||||
return api.SAMStatCheckCondition
|
return api.SAMStatCheckCondition
|
||||||
}
|
}
|
||||||
@@ -970,7 +994,9 @@ func SPCPRRegister(host int, cmd *api.SCSICommand) api.SAMStat {
|
|||||||
return api.SAMStatGood
|
return api.SAMStatGood
|
||||||
|
|
||||||
sense:
|
sense:
|
||||||
cmd.InSDBBuffer.Resid = 0
|
if cmd.InSDBBuffer != nil {
|
||||||
|
cmd.InSDBBuffer.Resid = 0
|
||||||
|
}
|
||||||
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
|
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
|
||||||
return api.SAMStatCheckCondition
|
return api.SAMStatCheckCondition
|
||||||
}
|
}
|
||||||
@@ -1032,7 +1058,9 @@ func SPCPRReserve(host int, cmd *api.SCSICommand) api.SAMStat {
|
|||||||
scsiResOp.Save(tgtName, devUUID)
|
scsiResOp.Save(tgtName, devUUID)
|
||||||
return api.SAMStatGood
|
return api.SAMStatGood
|
||||||
sense:
|
sense:
|
||||||
cmd.InSDBBuffer.Resid = 0
|
if cmd.InSDBBuffer != nil {
|
||||||
|
cmd.InSDBBuffer.Resid = 0
|
||||||
|
}
|
||||||
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
|
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
|
||||||
return api.SAMStatCheckCondition
|
return api.SAMStatCheckCondition
|
||||||
}
|
}
|
||||||
@@ -1082,7 +1110,9 @@ func SPCPRRelease(host int, cmd *api.SCSICommand) api.SAMStat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if curRes.Scope != resScope || curRes.Type != resType {
|
if curRes.Scope != resScope || curRes.Type != resType {
|
||||||
cmd.InSDBBuffer.Resid = 0
|
if cmd.InSDBBuffer != nil {
|
||||||
|
cmd.InSDBBuffer.Resid = 0
|
||||||
|
}
|
||||||
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_RELEASE_OF_PERSISTENT_RESERVATION)
|
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_RELEASE_OF_PERSISTENT_RESERVATION)
|
||||||
return api.SAMStatCheckCondition
|
return api.SAMStatCheckCondition
|
||||||
}
|
}
|
||||||
@@ -1113,7 +1143,9 @@ func SPCPRRelease(host int, cmd *api.SCSICommand) api.SAMStat {
|
|||||||
scsiResOp.Save(tgtName, devUUID)
|
scsiResOp.Save(tgtName, devUUID)
|
||||||
return api.SAMStatGood
|
return api.SAMStatGood
|
||||||
sense:
|
sense:
|
||||||
cmd.InSDBBuffer.Resid = 0
|
if cmd.InSDBBuffer != nil {
|
||||||
|
cmd.InSDBBuffer.Resid = 0
|
||||||
|
}
|
||||||
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
|
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
|
||||||
return api.SAMStatCheckCondition
|
return api.SAMStatCheckCondition
|
||||||
}
|
}
|
||||||
@@ -1167,7 +1199,9 @@ func SPCPRClear(host int, cmd *api.SCSICommand) api.SAMStat {
|
|||||||
scsiResOp.Save(tgtName, devUUID)
|
scsiResOp.Save(tgtName, devUUID)
|
||||||
return api.SAMStatGood
|
return api.SAMStatGood
|
||||||
sense:
|
sense:
|
||||||
cmd.InSDBBuffer.Resid = 0
|
if cmd.InSDBBuffer != nil {
|
||||||
|
cmd.InSDBBuffer.Resid = 0
|
||||||
|
}
|
||||||
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
|
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
|
||||||
return api.SAMStatCheckCondition
|
return api.SAMStatCheckCondition
|
||||||
}
|
}
|
||||||
@@ -1267,7 +1301,9 @@ func SPCPRPreempt(host int, cmd *api.SCSICommand) api.SAMStat {
|
|||||||
scsiResOp.Save(tgtName, devUUID)
|
scsiResOp.Save(tgtName, devUUID)
|
||||||
return api.SAMStatGood
|
return api.SAMStatGood
|
||||||
sense:
|
sense:
|
||||||
cmd.InSDBBuffer.Resid = 0
|
if cmd.InSDBBuffer != nil {
|
||||||
|
cmd.InSDBBuffer.Resid = 0
|
||||||
|
}
|
||||||
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
|
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
|
||||||
return api.SAMStatCheckCondition
|
return api.SAMStatCheckCondition
|
||||||
}
|
}
|
||||||
@@ -1353,7 +1389,9 @@ found:
|
|||||||
scsiResOp.Save(tgtName, devUUID)
|
scsiResOp.Save(tgtName, devUUID)
|
||||||
return api.SAMStatGood
|
return api.SAMStatGood
|
||||||
sense:
|
sense:
|
||||||
cmd.InSDBBuffer.Resid = 0
|
if cmd.InSDBBuffer != nil {
|
||||||
|
cmd.InSDBBuffer.Resid = 0
|
||||||
|
}
|
||||||
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
|
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
|
||||||
return api.SAMStatCheckCondition
|
return api.SAMStatCheckCondition
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user