PR implementation

This commit is contained in:
Le Zhang
2016-10-25 10:34:13 +08:00
parent f724702ecb
commit 82e6d230a2
19 changed files with 2382 additions and 75 deletions

View File

@@ -18,6 +18,9 @@ package api
import (
"bytes"
"errors"
"sync"
"github.com/satori/go.uuid"
)
type SCSICommandType byte
@@ -158,7 +161,7 @@ type SCSICommand struct {
OutSDBBuffer SCSIDataBuffer
RelTargetPortID uint16
// Command ITN ID
CommandITNID uint64
ITNexusID uuid.UUID
Offset uint64
TL uint32
SCB *bytes.Buffer
@@ -174,12 +177,8 @@ type SCSICommand struct {
}
type ITNexus struct {
ID uint64 `json:"id"`
Ctime uint64 `json:"ctime"`
Commands []SCSICommand `json:"-"`
Target *SCSITarget `json:"-"`
Host int `json:"host"`
Info string `json:"info"`
ID uuid.UUID `json:"id"` /*UUIDv1*/
Tag string `json:"Tag"` /*For protocal spec identifer*/
}
type ITNexusLuInfo struct {
@@ -199,15 +198,18 @@ type TargetPortGroup struct {
}
type SCSITarget struct {
Name string `json:"name"`
TID int `json:"tid"`
LID int `json:"lid"`
State SCSITargetState `json:"state"`
Devices LUNMap `json:"-"`
LUN0 *SCSILu `json:"-"`
ITNexus []*ITNexus `json:"itnexus"`
Name string `json:"name"`
TID int `json:"tid"`
LID int `json:"lid"`
State SCSITargetState `json:"state"`
Devices LUNMap `json:"-"`
LUN0 *SCSILu `json:"-"`
TargetPortGroups []*TargetPortGroup `json:"tpg"`
SCSITargetDriver interface{} `json:"-"`
ITNexusMutex sync.Mutex
ITNexus map[uuid.UUID]*ITNexus `json:"itnexus"`
}
type SCSITargetDriverState int
@@ -336,6 +338,7 @@ type BackingStore interface {
type SCSIDeviceProtocol interface {
PerformCommand(opcode int) interface{}
PerformServiceAction(opcode int, action uint8) interface{}
InitLu(lu *SCSILu) error
ConfigLu(lu *SCSILu) error
OnlineLu(lu *SCSILu) error
@@ -348,6 +351,14 @@ type ModePage struct {
Data []byte // Rest of mode page info
}
type SCSIReservation struct {
ID uuid.UUID //Internal Reservation ID
Key uint64
ITNexusID uuid.UUID
Scope uint8
Type uint8
}
type SCSILu struct {
Address uint64
Size uint64
@@ -355,7 +366,7 @@ type SCSILu struct {
Path string
BsoFlags int
BlockShift uint
ReserveID uint64
ReserveID uuid.UUID
Attrs SCSILuPhyAttribute
ModePages []ModePage
Storage BackingStore

View File

@@ -54,7 +54,7 @@ type iscsiConnection struct {
sessionType int
sessionParam []ISCSISessionParam
tid int
cid uint16
CID uint16
rxIOState int
txIOState int
refcount int

View File

@@ -30,6 +30,7 @@ import (
"github.com/gostor/gotgt/pkg/port"
"github.com/gostor/gotgt/pkg/scsi"
"github.com/gostor/gotgt/pkg/util"
"github.com/satori/go.uuid"
)
type ISCSITargetService struct {
@@ -165,7 +166,7 @@ func (s *ISCSITargetService) handler(events byte, conn *iscsiConnection) {
s.txHandler(conn)
}
if conn.state == CONN_STATE_CLOSE {
glog.Warningf("iscsi connection[%d] closed", conn.cid)
glog.Warningf("iscsi connection[%d] closed", conn.CID)
conn.close()
}
}
@@ -324,6 +325,7 @@ func (s *ISCSITargetService) iscsiExecLogin(conn *iscsiConnection) error {
{"DataSequenceInOrder", "Yes"},
}),
}
conn.CID = cmd.ConnID
pairs := util.ParseKVText(cmd.RawData)
if initiatorName, ok := pairs["InitiatorName"]; ok {
conn.initiator = initiatorName
@@ -376,11 +378,14 @@ func (s *ISCSITargetService) iscsiExecLogin(conn *iscsiConnection) error {
case SESSION_NORMAL:
if conn.session == nil {
// create a new session
sess, err := s.NewISCSISession(conn)
sess, err := s.NewISCSISession(conn, cmd.ISID)
if err != nil {
glog.Error(err)
return err
}
itnexus := &api.ITNexus{uuid.NewV1(), GeniSCSIITNexusID(sess)}
scsi.AddITNexus(&sess.Target.SCSITarget, itnexus)
sess.ITNexusID = itnexus.ID
conn.session = sess
}
case SESSION_DISCOVERY:
@@ -804,7 +809,7 @@ func (s *ISCSITargetService) iscsiExecTask(task *iscsiTask) error {
task.scmd.Direction = api.SCSIDataWrite
}
}
task.scmd.CommandITNID = task.conn.session.Tsih
task.scmd.ITNexusID = task.conn.session.ITNexusID
task.scmd.SCB = bytes.NewBuffer(cmd.CDB)
task.scmd.SCBLength = len(cmd.CDB)
task.scmd.Lun = cmd.LUN

View File

@@ -78,8 +78,8 @@ type iSCSITPGT struct {
type ISCSITarget struct {
api.SCSITarget
api.SCSITargetDriverCommon
TPGTs map[uint16]*iSCSITPGT
Sessions []*ISCSISession
TPGTs map[uint16]*iSCSITPGT /* Key is a TPGT number */
Sessions map[uint16]*ISCSISession /* Key is an TSIH */
SessionParam []ISCSISessionParam
Alias string
MaxSessions int
@@ -87,6 +87,23 @@ type ISCSITarget struct {
Rdma int
NopInterval int
NopCount int
TSIHCounter uint16
}
/*
* RFC 3720 iSCSI SSID = ISID , TPGT
* ISID is an 6 bytes number, TPGT is an 2 bytes number
* We combime ISID and TPGT together to be SSID
*/
func MakeSSID(ISID uint64, TPGT uint16) uint64 {
SSID := ISID<<16 | uint64(TPGT)
return SSID
}
func ParseSSID(SSID uint64) (uint64, uint16) {
TPGT := uint16(uint64(0xFFFF) & SSID)
ISID := SSID >> 16
return ISID, TPGT
}
func (tgt *ISCSITarget) FindTPG(portal string) (uint16, error) {
@@ -103,8 +120,10 @@ func (tgt *ISCSITarget) FindTPG(portal string) (uint16, error) {
func newISCSITarget(target *api.SCSITarget) *ISCSITarget {
return &ISCSITarget{
SCSITarget: *target,
TPGTs: make(map[uint16]*iSCSITPGT),
SCSITarget: *target,
TPGTs: make(map[uint16]*iSCSITPGT),
Sessions: make(map[uint16]*ISCSISession),
TSIHCounter: 1,
}
}

View File

@@ -20,6 +20,8 @@ import (
"fmt"
"math/rand"
"time"
"github.com/satori/go.uuid"
)
var (
@@ -149,8 +151,9 @@ type ISCSISession struct {
Initiator string
InitiatorAlias string
Target *ISCSITarget
Isid uint64
Tsih uint64
ISID uint64
TSIH uint64
ITNexusID uuid.UUID
ExpCmdSN uint32
// only one connection per session
@@ -215,7 +218,7 @@ type iscsiPdu struct {
}
// New creates a new session.
func (s *ISCSITargetService) NewISCSISession(conn *iscsiConnection) (*ISCSISession, error) {
func (s *ISCSITargetService) NewISCSISession(conn *iscsiConnection, isid uint64) (*ISCSISession, error) {
var (
target *ISCSITarget
tsih uint64
@@ -235,7 +238,7 @@ func (s *ISCSITargetService) NewISCSISession(conn *iscsiConnection) (*ISCSISessi
rand.Seed(int64(time.Now().UTC().Nanosecond()))
tsih = uint64(rand.Uint32())
for _, s := range target.Sessions {
if s.Tsih == tsih {
if s.TSIH == tsih {
tsih = 0
break
}
@@ -246,7 +249,8 @@ func (s *ISCSITargetService) NewISCSISession(conn *iscsiConnection) (*ISCSISessi
}
sess := &ISCSISession{
Tsih: tsih,
TSIH: tsih,
ISID: isid,
Initiator: conn.initiator,
InitiatorAlias: conn.initiatorAlias,
Target: target,
@@ -259,3 +263,14 @@ func (s *ISCSITargetService) NewISCSISession(conn *iscsiConnection) (*ISCSISessi
conn.session = sess
return sess, nil
}
/*
* iSCSI I_T nexus identifer = (iSCSI Initiator Name + 'i' + ISID, iSCSI Target Name + 't' + Portal Group Tag)
*/
func GeniSCSIITNexusID(sess *ISCSISession) string {
strID := fmt.Sprintf("%si0x%12x,%st%d",
sess.Initiator, sess.ISID,
sess.Target.SCSITarget.Name,
sess.Connections[0].tpgt)
return strID
}

View File

@@ -20,36 +20,33 @@ import (
"github.com/gostor/gotgt/pkg/util"
)
type SCSIPRServiceAction byte
type SCSIPRType byte
const (
/* PERSISTENT_RESERVE_IN service action codes */
PR_IN_READ_KEYS byte = 0x00
PR_IN_READ_RESERVATION byte = 0x01
PR_IN_REPORT_CAPABILITIES byte = 0x02
PR_IN_READ_FULL_STATUS byte = 0x03
var (
// PERSISTENT_RESERVE_IN service action codes
PR_IN_READ_KEYS SCSIPRServiceAction = 0x00
PR_IN_READ_RESERVATION SCSIPRServiceAction = 0x01
PR_IN_REPORT_CAPABILITIES SCSIPRServiceAction = 0x02
PR_IN_READ_FULL_STATUS SCSIPRServiceAction = 0x03
// PERSISTENT_RESERVE_OUT service action codes
PR_OUT_REGISTER SCSIPRServiceAction = 0x00
PR_OUT_RESERVE SCSIPRServiceAction = 0x01
PR_OUT_RELEASE SCSIPRServiceAction = 0x02
PR_OUT_CLEAR SCSIPRServiceAction = 0x03
PR_OUT_PREEMPT SCSIPRServiceAction = 0x04
PR_OUT_PREEMPT_AND_ABORT SCSIPRServiceAction = 0x05
PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY SCSIPRServiceAction = 0x06
PR_OUT_REGISTER_AND_MOVE SCSIPRServiceAction = 0x07
/* PERSISTENT_RESERVE_OUT service action codes */
PR_OUT_REGISTER byte = 0x00
PR_OUT_RESERVE byte = 0x01
PR_OUT_RELEASE byte = 0x02
PR_OUT_CLEAR byte = 0x03
PR_OUT_PREEMPT byte = 0x04
PR_OUT_PREEMPT_AND_ABORT byte = 0x05
PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY byte = 0x06
PR_OUT_REGISTER_AND_MOVE byte = 0x07
// Persistent Reservation scope
PR_LU_SCOPE byte = 0x00
// Persistent Reservation Type Mask format
PR_TYPE_WRITE_EXCLUSIVE SCSIPRType = 0x01
PR_TYPE_EXCLUSIVE_ACCESS SCSIPRType = 0x03
PR_TYPE_WRITE_EXCLUSIVE_REGONLY SCSIPRType = 0x05
PR_TYPE_EXCLUSIVE_ACCESS_REGONLY SCSIPRType = 0x06
PR_TYPE_WRITE_EXCLUSIVE_ALLREG SCSIPRType = 0x07
PR_TYPE_EXCLUSIVE_ACCESS_ALLREG SCSIPRType = 0x08
/* Persistent Reservation Type Mask format */
PR_TYPE_WRITE_EXCLUSIVE byte = 0x01
PR_TYPE_EXCLUSIVE_ACCESS byte = 0x03
PR_TYPE_WRITE_EXCLUSIVE_REGONLY byte = 0x05
PR_TYPE_EXCLUSIVE_ACCESS_REGONLY byte = 0x06
PR_TYPE_WRITE_EXCLUSIVE_ALLREG byte = 0x07
PR_TYPE_EXCLUSIVE_ACCESS_ALLREG byte = 0x08
)
const (

View File

@@ -11,8 +11,7 @@ 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.
*/
limitations under the License. */
package scsi
@@ -80,6 +79,10 @@ func NewLUN0() *api.SCSILu {
return lu
}
func GetReservation(dev *api.SCSILu, nexusID uint64) *api.SCSIReservation {
return nil
}
func luPerformCommand(tid int, cmd *api.SCSICommand) api.SAMStat {
op := int(cmd.SCB.Bytes()[0])
fn := cmd.Device.DeviceProtocol.PerformCommand(op)

View File

@@ -45,6 +45,16 @@ func (sbc SBCSCSIDeviceProtocol) PerformCommand(opcode int) interface{} {
return sbc.SCSIDeviceOps[opcode]
}
func (sbc SBCSCSIDeviceProtocol) PerformServiceAction(opcode int, action uint8) interface{} {
var sa *SCSIServiceAction
for _, sa = range sbc.SCSIDeviceOps[opcode].ServiceAction {
if sa.ServiceAction == action {
return sa
}
}
return nil
}
func (sbc SBCSCSIDeviceProtocol) InitLu(lu *api.SCSILu) error {
// init LU's phy attribute
lu.Attrs.DeviceType = sbc.DeviceType
@@ -158,8 +168,23 @@ 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_SENSE_10] = NewSCSIDeviceOperation(SBCModeSense, nil, PR_WE_FA|PR_WE_FN|PR_EA_FA|PR_EA_FN)
sbc.SCSIDeviceOps[api.PERSISTENT_RESERVE_IN] = NewSCSIDeviceOperation(SPCIllegalOp, nil, 0)
sbc.SCSIDeviceOps[api.PERSISTENT_RESERVE_OUT] = NewSCSIDeviceOperation(SPCIllegalOp, nil, 0)
sbc.SCSIDeviceOps[api.PERSISTENT_RESERVE_IN] = NewSCSIDeviceOperation(SPCServiceAction, []*SCSIServiceAction{
{ServiceAction: PR_IN_READ_KEYS, CommandPerformFunc: SPCPRReadKeys},
{ServiceAction: PR_IN_READ_RESERVATION, CommandPerformFunc: SPCPRReadReservation},
{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.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)
@@ -173,8 +198,10 @@ func NewSBCDevice(deviceType api.SCSIDeviceType) api.SCSIDeviceProtocol {
sbc.SCSIDeviceOps[api.SERVICE_ACTION_IN] = NewSCSIDeviceOperation(SBCServiceAction, nil, 0)
sbc.SCSIDeviceOps[api.REPORT_LUNS] = NewSCSIDeviceOperation(SPCReportLuns, nil, 0)
sbc.SCSIDeviceOps[api.MAINT_PROTOCOL_IN] = NewSCSIDeviceOperation(SPCServiceAction, nil, 0)
sbc.SCSIDeviceOps[api.EXCHANGE_MEDIUM] = NewSCSIDeviceOperation(SPCServiceAction, nil, 0)
sbc.SCSIDeviceOps[api.MAINT_PROTOCOL_IN] = NewSCSIDeviceOperation(SPCServiceAction, []*SCSIServiceAction{
{ServiceAction: 0x0C, CommandPerformFunc: SPCReportSupportedOperationCodes},
}, 0)
sbc.SCSIDeviceOps[api.EXCHANGE_MEDIUM] = NewSCSIDeviceOperation(SPCIllegalOp, nil, 0)
sbc.SCSIDeviceOps[api.READ_12] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN)
sbc.SCSIDeviceOps[api.WRITE_12] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_WE_FA|PR_EA_FA|PR_WE_FA|PR_WE_FN)
sbc.SCSIDeviceOps[api.WRITE_VERIFY_12] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN)
@@ -431,7 +458,7 @@ func SBCReserve(host int, cmd *api.SCSICommand) api.SAMStat {
func SBCRelease(host int, cmd *api.SCSICommand) api.SAMStat {
lun := *(*uint64)(unsafe.Pointer(&cmd.Lun))
if err := deviceRelease(cmd.Target.TID, cmd.CommandITNID, lun, false); err != nil {
if err := deviceRelease(cmd.Target.TID, cmd.ITNexusID, lun, false); err != nil {
return api.SAMStatReservationConflict
}

View File

@@ -25,6 +25,7 @@ import (
"github.com/golang/glog"
"github.com/gostor/gotgt/pkg/api"
"github.com/satori/go.uuid"
)
type SCSITargetService struct {
@@ -70,7 +71,7 @@ func (s *SCSITargetService) AddCommandQueue(tid int, scmd *api.SCSICommand) erro
}
scmd.Target = target
for _, it := range target.ITNexus {
if it.ID == scmd.CommandITNID {
if uuid.Equal(it.ID, scmd.ITNexusID) {
itn = it
break
}
@@ -99,13 +100,13 @@ func (s *SCSITargetService) AddCommandQueue(tid int, scmd *api.SCSICommand) erro
}
type SCSIServiceAction struct {
ServiceAction uint32
ServiceAction uint8
CommandPerformFunc api.CommandFunc
}
type SCSIDeviceOperation struct {
CommandPerformFunc api.CommandFunc
ServiceAction *SCSIServiceAction
ServiceAction []*SCSIServiceAction
PRConflictBits uint8
}
@@ -114,7 +115,7 @@ type BaseSCSIDeviceProtocol struct {
SCSIDeviceOps []SCSIDeviceOperation
}
func NewSCSIDeviceOperation(fn api.CommandFunc, sa *SCSIServiceAction, pr uint8) SCSIDeviceOperation {
func NewSCSIDeviceOperation(fn api.CommandFunc, sa []*SCSIServiceAction, pr uint8) SCSIDeviceOperation {
return SCSIDeviceOperation{
CommandPerformFunc: fn,
ServiceAction: sa,

324
pkg/scsi/scsi_pr.go Normal file
View File

@@ -0,0 +1,324 @@
package scsi
import (
"github.com/gostor/gotgt/pkg/api"
"github.com/satori/go.uuid"
)
type SCSIReservationOperator interface {
GetCurrentReservation(tgtName string, devUUID uint64) *api.SCSIReservation
SetCurrentReservation(tgtName string, devUUID uint64, res *api.SCSIReservation) bool
IsCurrentReservation(tgtName string, devUUID uint64, res *api.SCSIReservation) bool
GetPRGeneration(tgtName string, devUUID uint64) (uint32, bool)
IncPRGeneration(tgtName string, devUUID uint64) bool
AddReservation(tgtName string, devUUID uint64, res *api.SCSIReservation) bool
GetReservation(tgtName string, devUUID uint64, ITNexusID uuid.UUID) *api.SCSIReservation
GetReservationList(tgtName string, devUUID uint64) []*api.SCSIReservation
DeleteAndRemoveReservation(tgtName string, devUUID uint64, res *api.SCSIReservation)
RemoveReservation(tgtName string, devUUID uint64, res *api.SCSIReservation)
RemoveAllReservation(tgtName string, devUUID uint64)
IsKeyExists(tgtName string, devUUID uint64, key uint64) bool
Save(tgtName string, devUUID uint64) bool
}
var onePROperator SCSIReservationOperator
func GetSCSIReservationOperator() SCSIReservationOperator {
if onePROperator == nil {
onePROperator = &SCSISimpleReservationOperator{
targetReservations: make(map[string]SCSILUReservationMap),
}
}
return onePROperator
}
type SCSILUReservation struct {
TargetName string
DeviceUUID uint64
PRGeneration uint32
Reservations []*api.SCSIReservation
CurrentReservation *api.SCSIReservation
}
type SCSILUReservationMap map[uint64]*SCSILUReservation /* device uuid as the key */
type SCSISimpleReservationOperator struct {
SCSIReservationOperator
targetReservations map[string]SCSILUReservationMap /* target name as the key*/
}
func (op *SCSISimpleReservationOperator) InitLUReservation(tgtName string, devUUID uint64) {
var (
targetRes SCSILUReservationMap
ok bool
)
if targetRes, ok = op.targetReservations[tgtName]; !ok {
op.targetReservations[tgtName] = make(SCSILUReservationMap)
targetRes = op.targetReservations[tgtName]
}
if _, ok = targetRes[devUUID]; !ok {
targetRes[devUUID] = &SCSILUReservation{TargetName: tgtName,
DeviceUUID: devUUID,
PRGeneration: 0,
Reservations: []*api.SCSIReservation{},
CurrentReservation: nil,
}
}
}
func (op *SCSISimpleReservationOperator) GetReservation(tgtName string, devUUID uint64, ITNexusID uuid.UUID) *api.SCSIReservation {
var (
LURes *SCSILUReservation
SCSIRes *api.SCSIReservation
targetRes SCSILUReservationMap
ok bool
)
if targetRes, ok = op.targetReservations[tgtName]; !ok {
return nil
}
if LURes, ok = targetRes[devUUID]; !ok {
return nil
}
for _, SCSIRes = range LURes.Reservations {
if uuid.Equal(SCSIRes.ITNexusID, ITNexusID) {
return SCSIRes
}
}
return nil
}
func (op *SCSISimpleReservationOperator) GetPRGeneration(tgtName string, devUUID uint64) (uint32, bool) {
var (
LURes *SCSILUReservation
targetRes SCSILUReservationMap
ok bool
)
if targetRes, ok = op.targetReservations[tgtName]; !ok {
return 0, false
}
if LURes, ok = targetRes[devUUID]; !ok {
return 0, false
}
return LURes.PRGeneration, true
}
func (op *SCSISimpleReservationOperator) IncPRGeneration(tgtName string, devUUID uint64) bool {
var (
LURes *SCSILUReservation
targetRes SCSILUReservationMap
ok bool
)
if targetRes, ok = op.targetReservations[tgtName]; !ok {
return false
}
if LURes, ok = targetRes[devUUID]; !ok {
return false
}
LURes.PRGeneration++
return true
}
func (op *SCSISimpleReservationOperator) GetCurrentReservation(tgtName string, devUUID uint64) *api.SCSIReservation {
var (
LURes *SCSILUReservation
targetRes SCSILUReservationMap
ok bool
)
if targetRes, ok = op.targetReservations[tgtName]; !ok {
return nil
}
if LURes, ok = targetRes[devUUID]; !ok {
return nil
}
return LURes.CurrentReservation
}
func (op *SCSISimpleReservationOperator) SetCurrentReservation(tgtName string, devUUID uint64, res *api.SCSIReservation) bool {
var (
LURes *SCSILUReservation
targetRes SCSILUReservationMap
ok bool
)
if targetRes, ok = op.targetReservations[tgtName]; !ok {
return false
}
if LURes, ok = targetRes[devUUID]; !ok {
return false
}
LURes.CurrentReservation = res
return true
}
func (op *SCSISimpleReservationOperator) GetReservationList(tgtName string, devUUID uint64) []*api.SCSIReservation {
var (
LURes *SCSILUReservation
targetRes SCSILUReservationMap
ok bool
)
if targetRes, ok = op.targetReservations[tgtName]; !ok {
return nil
}
if LURes, ok = targetRes[devUUID]; !ok {
return nil
}
return LURes.Reservations
}
func (op *SCSISimpleReservationOperator) DeleteAndRemoveReservation(tgtName string, devUUID uint64, res *api.SCSIReservation) {
var (
i int = -1
ok bool
tmpRes *api.SCSIReservation
LURes *SCSILUReservation
targetRes SCSILUReservationMap
)
if targetRes, ok = op.targetReservations[tgtName]; !ok {
return
}
if LURes, ok = targetRes[devUUID]; !ok {
return
}
resArray := LURes.Reservations
curRes := LURes.CurrentReservation
for i, tmpRes = range resArray {
if tmpRes == res {
break
}
}
if i >= 0 {
resArray[i] = resArray[len(resArray)-1]
resArray[len(resArray)-1] = nil
resArray = resArray[:len(resArray)-1]
}
if curRes == nil {
return
}
if !op.IsCurrentReservation(tgtName, devUUID, res) {
return
}
if (curRes.Type != PR_TYPE_WRITE_EXCLUSIVE_ALLREG &&
curRes.Type != PR_TYPE_EXCLUSIVE_ACCESS_ALLREG) ||
len(resArray) == 0 {
curRes.Scope = 0
curRes.Type = 0
LURes.CurrentReservation = nil
for i, tmpRes = range resArray {
if tmpRes == res {
continue
}
//TODO send sense code
}
LURes.PRGeneration++
} else {
for i, tmpRes = range resArray {
if tmpRes != res {
//kep scope and type
LURes.CurrentReservation = tmpRes
tmpRes.Scope = curRes.Scope
tmpRes.Type = curRes.Type
break
}
}
LURes.PRGeneration++
}
}
func (op *SCSISimpleReservationOperator) RemoveReservation(tgtName string, devUUID uint64, res *api.SCSIReservation) {
var (
i int = -1
tmpRes *api.SCSIReservation
)
resArray := op.GetReservationList(tgtName, devUUID)
for i, tmpRes = range resArray {
if tmpRes == res {
break
}
}
if i >= 0 {
resArray[i] = resArray[len(resArray)-1]
resArray[len(resArray)-1] = nil
resArray = resArray[:len(resArray)-1]
}
}
func (op *SCSISimpleReservationOperator) AddReservation(tgtName string, devUUID uint64, res *api.SCSIReservation) bool {
var (
LURes *SCSILUReservation
targetRes SCSILUReservationMap
ok bool
)
if targetRes, ok = op.targetReservations[tgtName]; !ok {
return false
}
if LURes, ok = targetRes[devUUID]; !ok {
return false
}
LURes.Reservations = append(LURes.Reservations, res)
return true
}
func (op *SCSISimpleReservationOperator) IsKeyExists(tgtName string, devUUID uint64, key uint64) bool {
resList := op.GetReservationList(tgtName, devUUID)
for _, tmpRes := range resList {
if tmpRes.Key == key {
return true
}
}
return false
}
func (op *SCSISimpleReservationOperator) IsCurrentReservation(tgtName string, devUUID uint64, res *api.SCSIReservation) bool {
curRes := op.GetCurrentReservation(tgtName, devUUID)
if curRes == nil {
return false
}
if curRes.Type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG ||
curRes.Type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG {
return true
}
if curRes == res {
return true
}
return false
}
func (op *SCSISimpleReservationOperator) RemoveAllReservation(tgtName string, devUUID uint64) {
var (
LURes *SCSILUReservation
targetRes SCSILUReservationMap
ok bool
)
if targetRes, ok = op.targetReservations[tgtName]; !ok {
return
}
if LURes, ok = targetRes[devUUID]; !ok {
return
}
LURes.Reservations = []*api.SCSIReservation{}
}
func (op *SCSISimpleReservationOperator) Save(tgtName string, devUUID uint64) bool {
return true
}

View File

@@ -65,6 +65,8 @@ func GetTargetLUNMap(tgtName string) api.LUNMap {
}
func InitSCSILUMap(config *config.Config) error {
var simpleOp *SCSISimpleReservationOperator
var ok bool
globalSCSILUMap.mutex.Lock()
defer globalSCSILUMap.mutex.Unlock()
@@ -83,6 +85,11 @@ func InitSCSILUMap(config *config.Config) error {
return errors.New("LU Number must be a number")
}
mappingLUN(deviceID, lun, tgtName)
//Init SCSISimpleReservationOperator
op := GetSCSIReservationOperator()
if simpleOp, ok = op.(*SCSISimpleReservationOperator); ok {
simpleOp.InitLUReservation(tgtName, deviceID)
}
}
}
return nil

View File

@@ -25,6 +25,7 @@ import (
"github.com/golang/glog"
"github.com/gostor/gotgt/pkg/api"
"github.com/gostor/gotgt/pkg/util"
"github.com/satori/go.uuid"
)
func SPCIllegalOp(host int, cmd *api.SCSICommand) api.SAMStat {
@@ -568,9 +569,7 @@ func reportOpcodeOne(cmd *api.SCSICommand, rctd int, opcode byte, rsa uint16, se
return nil
}
// This is useful for the various commands using the SERVICE ACTION format.
func SPCServiceAction(host int, cmd *api.SCSICommand) api.SAMStat {
// TODO
func SPCReportSupportedOperationCodes(host int, cmd *api.SCSICommand) api.SAMStat {
scb := cmd.SCB.Bytes()
reporting_options := scb[2] & 0x07
opcode := scb[3]
@@ -609,15 +608,60 @@ sense:
return api.SAMStatCheckCondition
}
// 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()
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 {
fnop := serviceAction.(*SCSIServiceAction)
return fnop.CommandPerformFunc(host, cmd)
}
}
func SPCPRReadKeys(host int, cmd *api.SCSICommand) api.SAMStat {
allocationLength := util.GetUnalignedUint32(cmd.SCB.Bytes()[7:9])
var (
buf = &bytes.Buffer{}
data []byte = []byte{}
addBuf = &bytes.Buffer{}
allocationLength uint16
additionLength uint32
)
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
}
if cmd.InSDBBuffer.Length < allocationLength {
goto sense
for _, res := range resList {
addBuf.Write(util.MarshalUint64(res.Key))
}
// TODO
additionLength = uint32(len(addBuf.Bytes()))
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)
}
cmd.InSDBBuffer.Resid = int32(additionLength)
return api.SAMStatGood
sense:
cmd.InSDBBuffer.Resid = 0
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
@@ -625,7 +669,59 @@ sense:
}
func SPCPRReadReservation(host int, cmd *api.SCSICommand) api.SAMStat {
var (
buf = &bytes.Buffer{}
data []byte = []byte{}
addBuf = &bytes.Buffer{}
allocationLength uint16
additionLength uint32
)
tgtName := cmd.Target.Name
devUUID := cmd.Device.UUID
scsiResOp := GetSCSIReservationOperator()
PRGeneration, _ := scsiResOp.GetPRGeneration(tgtName, devUUID)
curRes := scsiResOp.GetCurrentReservation(tgtName, devUUID)
length, _ := SCSICDBBufXLength(cmd.SCB.Bytes())
allocationLength = uint16(length)
if allocationLength < 8 {
goto sense
}
if curRes == nil {
additionLength = 0
} else {
addBuf.Write(util.MarshalUint64(curRes.Key))
//Obsolete
addBuf.WriteByte(0x00)
addBuf.WriteByte(0x00)
addBuf.WriteByte(0x00)
addBuf.WriteByte(0x00)
//Reserved
addBuf.WriteByte(0x00)
//SCOPE and TYPE
scope_type := (curRes.Scope << 4) | curRes.Type
addBuf.WriteByte(scope_type)
additionLength = uint32(0x10)
}
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)
}
cmd.InSDBBuffer.Resid = int32(additionLength)
return api.SAMStatGood
sense:
cmd.InSDBBuffer.Resid = 0
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
return api.SAMStatCheckCondition
}
func SPCPRReportCapabilities(host int, cmd *api.SCSICommand) api.SAMStat {
@@ -672,28 +768,466 @@ sense:
return api.SAMStatCheckCondition
}
func reservationCheck(host int, cmd *api.SCSICommand) bool {
var (
paramLen uint32
buf []byte = cmd.OutSDBBuffer.Buffer.Bytes()
)
length, _ := SCSICDBBufXLength(cmd.SCB.Bytes())
paramLen = uint32(length)
if paramLen != 24 {
return false
}
spec_i_pt := uint8(buf[20] & 0x08)
all_tg_pt := uint8(buf[20] & 0x04)
aptpl := uint8(buf[20] & 0x01)
/* Currently, We don't support these flags */
if (spec_i_pt | all_tg_pt | aptpl) > 0 {
return false
}
return true
}
func SPCPRRegister(host int, cmd *api.SCSICommand) api.SAMStat {
var (
buf []byte = cmd.OutSDBBuffer.Buffer.Bytes()
scb []byte = cmd.SCB.Bytes()
ignoreKey bool = false
ok bool = false
resKey uint64
sAResKey uint64
)
tgtName := cmd.Target.Name
devUUID := cmd.Device.UUID
scsiResOp := GetSCSIReservationOperator()
res := scsiResOp.GetReservation(tgtName, devUUID, cmd.ITNexusID)
if scb[1] == PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY {
ignoreKey = true
}
ok = reservationCheck(host, cmd)
if !ok {
goto sense
}
resKey = util.GetUnalignedUint64(buf[0:8])
sAResKey = util.GetUnalignedUint64(buf[8:16])
if res != nil {
if ignoreKey || resKey == res.Key {
if sAResKey != 0 {
res.Key = sAResKey
} else {
scsiResOp.DeleteAndRemoveReservation(tgtName, devUUID, res)
}
} else {
return api.SAMStatReservationConflict
}
} else {
if ignoreKey || resKey == 0 {
if sAResKey != 0 {
newRes := &api.SCSIReservation{
ID: uuid.NewV1(),
Key: sAResKey,
ITNexusID: cmd.ITNexusID,
}
scsiResOp.AddReservation(tgtName, devUUID, newRes)
}
} else {
return api.SAMStatReservationConflict
}
}
scsiResOp.IncPRGeneration(tgtName, devUUID)
scsiResOp.Save(tgtName, devUUID)
return api.SAMStatGood
sense:
cmd.InSDBBuffer.Resid = 0
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
return api.SAMStatCheckCondition
}
func SPCPRReserve(host int, cmd *api.SCSICommand) api.SAMStat {
var (
scb []byte = cmd.SCB.Bytes()
curRes *api.SCSIReservation
res *api.SCSIReservation
ok bool = false
resScope uint8
resType uint8
)
tgtName := cmd.Target.Name
devUUID := cmd.Device.UUID
scsiResOp := GetSCSIReservationOperator()
ok = reservationCheck(host, cmd)
if !ok {
goto sense
}
resScope = scb[2] & 0xf0 >> 4
resType = scb[2] & 0x0f
switch resType {
case PR_TYPE_WRITE_EXCLUSIVE_REGONLY,
PR_TYPE_EXCLUSIVE_ACCESS_REGONLY,
PR_TYPE_WRITE_EXCLUSIVE_ALLREG,
PR_TYPE_EXCLUSIVE_ACCESS_ALLREG:
break
default:
goto sense
}
if resScope != PR_LU_SCOPE {
goto sense
}
res = scsiResOp.GetReservation(tgtName, devUUID, cmd.ITNexusID)
if res == nil {
return api.SAMStatReservationConflict
}
curRes = scsiResOp.GetCurrentReservation(tgtName, devUUID)
if curRes != nil {
if !scsiResOp.IsCurrentReservation(tgtName, devUUID, res) {
return api.SAMStatReservationConflict
}
if curRes.Type != resType ||
curRes.Scope != resScope {
return api.SAMStatReservationConflict
}
}
res.Scope = resScope
res.Type = resType
scsiResOp.SetCurrentReservation(tgtName, devUUID, res)
scsiResOp.Save(tgtName, devUUID)
return api.SAMStatGood
sense:
cmd.InSDBBuffer.Resid = 0
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
return api.SAMStatCheckCondition
}
func SPCPRRelease(host int, cmd *api.SCSICommand) api.SAMStat {
var (
buf []byte = cmd.OutSDBBuffer.Buffer.Bytes()
scb []byte = cmd.SCB.Bytes()
curRes *api.SCSIReservation
res *api.SCSIReservation
resList []*api.SCSIReservation
ok bool = false
resKey uint64
resScope uint8
resType uint8
)
tgtName := cmd.Target.Name
devUUID := cmd.Device.UUID
scsiResOp := GetSCSIReservationOperator()
ok = reservationCheck(host, cmd)
if !ok {
goto sense
}
resScope = scb[2] & 0xf0 >> 4
resType = scb[2] & 0x0f
resKey = util.GetUnalignedUint64(buf[0:8])
res = scsiResOp.GetReservation(tgtName, devUUID, cmd.ITNexusID)
if res == nil {
return api.SAMStatReservationConflict
}
curRes = scsiResOp.GetCurrentReservation(tgtName, devUUID)
if curRes == nil {
return api.SAMStatGood
}
if !scsiResOp.IsCurrentReservation(tgtName, devUUID, res) {
return api.SAMStatGood
}
if resKey != res.Key {
return api.SAMStatReservationConflict
}
if curRes.Scope != resScope || curRes.Type != resType {
cmd.InSDBBuffer.Resid = 0
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_RELEASE_OF_PERSISTENT_RESERVATION)
return api.SAMStatCheckCondition
}
scsiResOp.SetCurrentReservation(tgtName, devUUID, nil)
res.Scope = 0
res.Type = 0
switch resType {
case PR_TYPE_WRITE_EXCLUSIVE,
PR_TYPE_EXCLUSIVE_ACCESS,
PR_TYPE_WRITE_EXCLUSIVE_REGONLY,
PR_TYPE_EXCLUSIVE_ACCESS_REGONLY,
PR_TYPE_WRITE_EXCLUSIVE_ALLREG,
PR_TYPE_EXCLUSIVE_ACCESS_ALLREG:
break
default:
goto sense
}
resList = scsiResOp.GetReservationList(tgtName, devUUID)
for _, tmpRes := range resList {
if tmpRes.ID == res.ID {
continue
}
//TODO send sense code
}
scsiResOp.Save(tgtName, devUUID)
return api.SAMStatGood
sense:
cmd.InSDBBuffer.Resid = 0
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
return api.SAMStatCheckCondition
}
func SPCPRClear(host int, cmd *api.SCSICommand) api.SAMStat {
var (
buf []byte = cmd.OutSDBBuffer.Buffer.Bytes()
curRes *api.SCSIReservation
res *api.SCSIReservation
ok bool = false
resKey uint64
)
tgtName := cmd.Target.Name
devUUID := cmd.Device.UUID
scsiResOp := GetSCSIReservationOperator()
resList := scsiResOp.GetReservationList(tgtName, devUUID)
ok = reservationCheck(host, cmd)
if !ok {
goto sense
}
resKey = util.GetUnalignedUint64(buf[0:8])
res = scsiResOp.GetReservation(tgtName, devUUID, cmd.ITNexusID)
if res == nil {
return api.SAMStatReservationConflict
}
if res.Key != resKey {
return api.SAMStatReservationConflict
}
curRes = scsiResOp.GetCurrentReservation(tgtName, devUUID)
if curRes != nil {
curRes.Scope = 0
curRes.Type = 0
scsiResOp.SetCurrentReservation(tgtName, devUUID, nil)
}
for _, tmpRes := range resList {
if tmpRes != res {
//TODO send sense code
}
scsiResOp.DeleteAndRemoveReservation(tgtName, devUUID, tmpRes)
}
scsiResOp.IncPRGeneration(tgtName, devUUID)
scsiResOp.Save(tgtName, devUUID)
return api.SAMStatGood
sense:
cmd.InSDBBuffer.Resid = 0
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
return api.SAMStatCheckCondition
}
func SPCPRPreempt(host int, cmd *api.SCSICommand) api.SAMStat {
var (
buf []byte = cmd.OutSDBBuffer.Buffer.Bytes()
scb []byte = cmd.SCB.Bytes()
ok bool = false
resKey uint64
sAResKey uint64
res *api.SCSIReservation
curRes *api.SCSIReservation
resReleased bool
removeAllRes bool
resScope uint8
resType uint8
)
tgtName := cmd.Target.Name
devUUID := cmd.Device.UUID
scsiResOp := GetSCSIReservationOperator()
resList := scsiResOp.GetReservationList(tgtName, devUUID)
ok = reservationCheck(host, cmd)
if !ok {
goto sense
}
resScope = scb[2] & 0xf0 >> 4
resType = scb[2] & 0x0f
resKey = util.GetUnalignedUint64(buf[0:8])
sAResKey = util.GetUnalignedUint64(buf[8:16])
res = scsiResOp.GetReservation(tgtName, devUUID, cmd.ITNexusID)
if res == nil {
return api.SAMStatReservationConflict
}
if res.Key != resKey {
return api.SAMStatReservationConflict
}
if sAResKey != 0 {
ok = scsiResOp.IsKeyExists(tgtName, devUUID, sAResKey)
if ok {
return api.SAMStatReservationConflict
}
}
curRes = scsiResOp.GetCurrentReservation(tgtName, devUUID)
if curRes != nil {
if curRes.Type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG ||
curRes.Type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG {
if sAResKey == 0 {
if resType != curRes.Type ||
resScope != curRes.Scope {
resReleased = true
}
res.Type = resType
res.Scope = resScope
scsiResOp.SetCurrentReservation(tgtName, devUUID, res)
removeAllRes = true
}
} else {
if curRes.Key == resKey {
if resType != curRes.Type ||
resScope != curRes.Scope {
resReleased = true
}
res.Type = resType
res.Scope = resScope
scsiResOp.SetCurrentReservation(tgtName, devUUID, res)
} else {
if sAResKey == 0 {
goto sense
}
}
}
}
for _, tmpRes := range resList {
if tmpRes == res {
continue
}
if res.Key == resKey || removeAllRes {
//TODO send sense code
scsiResOp.RemoveReservation(tgtName, devUUID, res)
} else {
if resReleased {
//TODO send sense code
}
}
}
scsiResOp.IncPRGeneration(tgtName, devUUID)
scsiResOp.Save(tgtName, devUUID)
return api.SAMStatGood
sense:
cmd.InSDBBuffer.Resid = 0
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
return api.SAMStatCheckCondition
}
func SPCPRRegisterAndMove(host int, cmd *api.SCSICommand) api.SAMStat {
var (
buf []byte = cmd.OutSDBBuffer.Buffer.Bytes()
scb []byte = cmd.SCB.Bytes()
resKey uint64
sAResKey uint64
curRes, dstReg, res *api.SCSIReservation
paramListLen uint32
unreg uint8
aptpl uint8
tpidDataLen uint32
//idLen uint32
)
tgtName := cmd.Target.Name
devUUID := cmd.Device.UUID
scsiResOp := GetSCSIReservationOperator()
resList := scsiResOp.GetReservationList(tgtName, devUUID)
paramListLen = util.GetUnalignedUint32(scb[5:9])
if paramListLen < 24 {
goto sense
}
aptpl = buf[17] & 0x01
if aptpl != 0 { /* no reported in capabilities */
goto sense
}
unreg = buf[17] & 0x02
resKey = util.GetUnalignedUint64(buf[0:8])
sAResKey = util.GetUnalignedUint64(buf[8:16])
tpidDataLen = util.GetUnalignedUint32(buf[20:25])
if tpidDataLen < 24 || (tpidDataLen%4) != 0 {
goto sense
}
if (paramListLen - 24) < tpidDataLen {
goto sense
}
res = scsiResOp.GetReservation(tgtName, devUUID, cmd.ITNexusID)
curRes = scsiResOp.GetCurrentReservation(tgtName, devUUID)
if res == nil {
if curRes != nil {
return api.SAMStatReservationConflict
} else {
goto sense
}
}
if scsiResOp.IsCurrentReservation(tgtName, devUUID, res) {
return api.SAMStatGood
}
if res.Key != resKey {
return api.SAMStatReservationConflict
}
if sAResKey == 0 {
return api.SAMStatReservationConflict
}
for _, dstReg = range resList {
if dstReg.Key == sAResKey {
goto found
}
}
goto sense
found:
//TODO check transportid
scsiResOp.SetCurrentReservation(tgtName, devUUID, dstReg)
if unreg != 0 {
scsiResOp.RemoveReservation(tgtName, devUUID, res)
}
scsiResOp.IncPRGeneration(tgtName, devUUID)
scsiResOp.Save(tgtName, devUUID)
return api.SAMStatGood
sense:
cmd.InSDBBuffer.Resid = 0
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
return api.SAMStatCheckCondition
}
/*

View File

@@ -22,6 +22,7 @@ import (
"github.com/golang/glog"
"github.com/gostor/gotgt/pkg/api"
"github.com/satori/go.uuid"
)
func (s *SCSITargetService) NewSCSITarget(tid int, driverName, name string) (*api.SCSITarget, error) {
@@ -34,6 +35,7 @@ func (s *SCSITargetService) NewSCSITarget(tid int, driverName, name string) (*ap
Name: name,
TID: tid,
TargetPortGroups: []*api.TargetPortGroup{},
ITNexus: make(map[uuid.UUID]*api.ITNexus),
}
tpg := &api.TargetPortGroup{0, []*api.SCSITargetPort{}}
s.Targets = append(s.Targets, target)
@@ -65,6 +67,25 @@ func FindTargetPort(target *api.SCSITarget, relPortID uint16) *api.SCSITargetPor
return nil
}
func AddITNexus(target *api.SCSITarget, itnexus *api.ITNexus) bool {
var ret bool = true
target.ITNexusMutex.Lock()
defer target.ITNexusMutex.Unlock()
if _, ok := target.ITNexus[itnexus.ID]; !ok {
target.ITNexus[itnexus.ID] = itnexus
ret = true
} else {
ret = false
}
return ret
}
func RemoveITNexus(target *api.SCSITarget, itnexus *api.ITNexus) {
target.ITNexusMutex.Lock()
defer target.ITNexusMutex.Unlock()
delete(target.ITNexus, itnexus.ID)
}
func deviceReserve(cmd *api.SCSICommand) error {
var lu *api.SCSILu
lun := *(*uint64)(unsafe.Pointer(&cmd.Lun))
@@ -80,15 +101,15 @@ func deviceReserve(cmd *api.SCSICommand) error {
return nil
}
if lu.ReserveID != 0 && lu.ReserveID != cmd.CommandITNID {
glog.Errorf("already reserved %d, %d", lu.ReserveID, cmd.CommandITNID)
if !uuid.Equal(lu.ReserveID, uuid.Nil) && uuid.Equal(lu.ReserveID, cmd.ITNexusID) {
glog.Errorf("already reserved %d, %d", lu.ReserveID, cmd.ITNexusID)
return fmt.Errorf("already reserved")
}
lu.ReserveID = cmd.CommandITNID
lu.ReserveID = cmd.ITNexusID
return nil
}
func deviceRelease(tid int, itn, lun uint64, force bool) error {
func deviceRelease(tid int, itn uuid.UUID, lun uint64, force bool) error {
// TODO
return nil
}