run the basic process with iscsi driver
This commit is contained in:
58
citd.go
58
citd.go
@@ -19,13 +19,69 @@ package main
|
||||
|
||||
import (
|
||||
"net"
|
||||
"os"
|
||||
"reflect"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/gostor/gotgt/pkg/api"
|
||||
"github.com/gostor/gotgt/pkg/scsi"
|
||||
)
|
||||
|
||||
func main() {
|
||||
_, err := net.Listen("tcp", ":3260")
|
||||
l, err := net.Listen("tcp", ":3260")
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer l.Close()
|
||||
t, err := scsi.NewTarget(0, "iscsi", "test-iscsi-target")
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
conns := make(map[string]net.Conn)
|
||||
|
||||
for {
|
||||
glog.Info("Listening ...")
|
||||
conn, err := l.Accept()
|
||||
checkError(err, "Accept")
|
||||
glog.Info("Accepting ...")
|
||||
conns[conn.RemoteAddr().String()] = conn
|
||||
// start a new thread to do with this command
|
||||
go Handler(conn, t)
|
||||
}
|
||||
}
|
||||
|
||||
func checkError(err error, info string) (res bool) {
|
||||
|
||||
if err != nil {
|
||||
glog.Error(info + " " + err.Error())
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func Handler(conn net.Conn, tgt *api.SCSITarget) {
|
||||
|
||||
glog.Infof("connection is connected from %s...\n", conn.RemoteAddr().String())
|
||||
|
||||
buf := make([]byte, 1024)
|
||||
for {
|
||||
lenght, err := conn.Read(buf)
|
||||
if checkError(err, "Connection") == false {
|
||||
conn.Close()
|
||||
break
|
||||
}
|
||||
if lenght > 0 {
|
||||
buf[lenght] = 0
|
||||
}
|
||||
v := reflect.ValueOf(tgt.SCSITargetDriver)
|
||||
iscsit := v.MethodByName("ProcessCommand")
|
||||
in := make([]reflect.Value, 1)
|
||||
in[0] = reflect.ValueOf(buf[0:lenght])
|
||||
res := iscsit.Call(in)[0]
|
||||
b := res.Bytes()
|
||||
glog.Infof("%s\n", string(b))
|
||||
conn.Write(b)
|
||||
}
|
||||
}
|
||||
|
||||
307
pkg/api/types.go
Normal file
307
pkg/api/types.go
Normal file
@@ -0,0 +1,307 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
)
|
||||
|
||||
type SCSICommandType byte
|
||||
|
||||
var (
|
||||
TEST_UNIT_READY SCSICommandType = 0x00
|
||||
REZERO_UNIT SCSICommandType = 0x01
|
||||
REQUEST_SENSE SCSICommandType = 0x03
|
||||
FORMAT_UNIT SCSICommandType = 0x04
|
||||
READ_BLOCK_LIMITS SCSICommandType = 0x05
|
||||
REASSIGN_BLOCKS SCSICommandType = 0x07
|
||||
INITIALIZE_ELEMENT_STATUS SCSICommandType = 0x07
|
||||
READ_6 SCSICommandType = 0x08
|
||||
WRITE_6 SCSICommandType = 0x0a
|
||||
SEEK_6 SCSICommandType = 0x0b
|
||||
READ_REVERSE SCSICommandType = 0x0f
|
||||
WRITE_FILEMARKS SCSICommandType = 0x10
|
||||
SPACE SCSICommandType = 0x11
|
||||
INQUIRY SCSICommandType = 0x12
|
||||
RECOVER_BUFFERED_DATA SCSICommandType = 0x14
|
||||
MODE_SELECT SCSICommandType = 0x15
|
||||
RESERVE SCSICommandType = 0x16
|
||||
RELEASE SCSICommandType = 0x17
|
||||
COPY SCSICommandType = 0x18
|
||||
ERASE SCSICommandType = 0x19
|
||||
MODE_SENSE SCSICommandType = 0x1a
|
||||
START_STOP SCSICommandType = 0x1b
|
||||
RECEIVE_DIAGNOSTIC SCSICommandType = 0x1c
|
||||
SEND_DIAGNOSTIC SCSICommandType = 0x1d
|
||||
ALLOW_MEDIUM_REMOVAL SCSICommandType = 0x1e
|
||||
|
||||
SET_WINDOW SCSICommandType = 0x24
|
||||
READ_CAPACITY SCSICommandType = 0x25
|
||||
READ_10 SCSICommandType = 0x28
|
||||
WRITE_10 SCSICommandType = 0x2a
|
||||
SEEK_10 SCSICommandType = 0x2b
|
||||
POSITION_TO_ELEMENT SCSICommandType = 0x2b
|
||||
WRITE_VERIFY SCSICommandType = 0x2e
|
||||
VERIFY_10 SCSICommandType = 0x2f
|
||||
SEARCH_HIGH SCSICommandType = 0x30
|
||||
SEARCH_EQUAL SCSICommandType = 0x31
|
||||
SEARCH_LOW SCSICommandType = 0x32
|
||||
SET_LIMITS SCSICommandType = 0x33
|
||||
PRE_FETCH_10 SCSICommandType = 0x34
|
||||
READ_POSITION SCSICommandType = 0x34
|
||||
SYNCHRONIZE_CACHE SCSICommandType = 0x35
|
||||
LOCK_UNLOCK_CACHE SCSICommandType = 0x36
|
||||
READ_DEFECT_DATA SCSICommandType = 0x37
|
||||
INITIALIZE_ELEMENT_STATUS_WITH_RANGE SCSICommandType = 0x37
|
||||
MEDIUM_SCAN SCSICommandType = 0x38
|
||||
COMPARE SCSICommandType = 0x39
|
||||
COPY_VERIFY SCSICommandType = 0x3a
|
||||
WRITE_BUFFER SCSICommandType = 0x3b
|
||||
READ_BUFFER SCSICommandType = 0x3c
|
||||
UPDATE_BLOCK SCSICommandType = 0x3d
|
||||
READ_LONG SCSICommandType = 0x3e
|
||||
WRITE_LONG SCSICommandType = 0x3f
|
||||
CHANGE_DEFINITION SCSICommandType = 0x40
|
||||
WRITE_SAME SCSICommandType = 0x41
|
||||
UNMAP SCSICommandType = 0x42
|
||||
READ_TOC SCSICommandType = 0x43
|
||||
GET_CONFIGURATION SCSICommandType = 0x46
|
||||
LOG_SELECT SCSICommandType = 0x4c
|
||||
LOG_SENSE SCSICommandType = 0x4d
|
||||
READ_DISK_INFO SCSICommandType = 0x51
|
||||
READ_TRACK_INFO SCSICommandType = 0x52
|
||||
MODE_SELECT_10 SCSICommandType = 0x55
|
||||
RESERVE_10 SCSICommandType = 0x56
|
||||
RELEASE_10 SCSICommandType = 0x57
|
||||
MODE_SENSE_10 SCSICommandType = 0x5a
|
||||
CLOSE_TRACK SCSICommandType = 0x5b
|
||||
READ_BUFFER_CAP SCSICommandType = 0x5c
|
||||
PERSISTENT_RESERVE_IN SCSICommandType = 0x5e
|
||||
PERSISTENT_RESERVE_OUT SCSICommandType = 0x5f
|
||||
VARLEN_CDB SCSICommandType = 0x7f
|
||||
READ_16 SCSICommandType = 0x88
|
||||
COMPARE_AND_WRITE SCSICommandType = 0x89
|
||||
WRITE_16 SCSICommandType = 0x8a
|
||||
ORWRITE_16 SCSICommandType = 0x8b
|
||||
WRITE_VERIFY_16 SCSICommandType = 0x8e
|
||||
VERIFY_16 SCSICommandType = 0x8f
|
||||
PRE_FETCH_16 SCSICommandType = 0x90
|
||||
SYNCHRONIZE_CACHE_16 SCSICommandType = 0x91
|
||||
WRITE_SAME_16 SCSICommandType = 0x93
|
||||
SERVICE_ACTION_IN SCSICommandType = 0x9e
|
||||
SAI_READ_CAPACITY_16 SCSICommandType = 0x10
|
||||
SAI_GET_LBA_STATUS SCSICommandType = 0x12
|
||||
REPORT_LUNS SCSICommandType = 0xa0
|
||||
MAINT_PROTOCOL_IN SCSICommandType = 0xa3
|
||||
MOVE_MEDIUM SCSICommandType = 0xa5
|
||||
EXCHANGE_MEDIUM SCSICommandType = 0xa6
|
||||
READ_12 SCSICommandType = 0xa8
|
||||
WRITE_12 SCSICommandType = 0xaa
|
||||
GET_PERFORMACE SCSICommandType = 0xac
|
||||
READ_DVD_STRUCTURE SCSICommandType = 0xad
|
||||
WRITE_VERIFY_12 SCSICommandType = 0xae
|
||||
VERIFY_12 SCSICommandType = 0xaf
|
||||
SEARCH_HIGH_12 SCSICommandType = 0xb0
|
||||
SEARCH_EQUAL_12 SCSICommandType = 0xb1
|
||||
SEARCH_LOW_12 SCSICommandType = 0xb2
|
||||
READ_ELEMENT_STATUS SCSICommandType = 0xb8
|
||||
SEND_VOLUME_TAG SCSICommandType = 0xb6
|
||||
SET_STREAMING SCSICommandType = 0xb6
|
||||
SET_CD_SPEED SCSICommandType = 0xbb
|
||||
WRITE_LONG_2 SCSICommandType = 0xea
|
||||
)
|
||||
|
||||
type SCSITargetState int
|
||||
|
||||
var (
|
||||
TargetOnline SCSITargetState = 1
|
||||
TargetReady SCSITargetState = 2
|
||||
)
|
||||
|
||||
type SCSIDataDirection int
|
||||
|
||||
const (
|
||||
SCSIDataNone = iota
|
||||
SCSIDataWrite
|
||||
SCSIDataRead
|
||||
SCSIDataBidirection
|
||||
)
|
||||
|
||||
type SCSIDataBuffer struct {
|
||||
Buffer *bytes.Buffer
|
||||
Length uint32
|
||||
TransferLength uint32
|
||||
Resid int32
|
||||
}
|
||||
|
||||
type SCSICommand struct {
|
||||
Target *SCSITarget
|
||||
DeviceID uint64
|
||||
Device *SCSILu
|
||||
State uint64
|
||||
Direction SCSIDataDirection
|
||||
InSDBBuffer SCSIDataBuffer
|
||||
OutSDBBuffer SCSIDataBuffer
|
||||
// Command ITN ID
|
||||
CommandITNID uint64
|
||||
Offset uint64
|
||||
TL uint32
|
||||
SCB *bytes.Buffer
|
||||
SCBLength int
|
||||
Lun []uint8
|
||||
Attribute int
|
||||
Tag uint64
|
||||
Result byte
|
||||
SenseBuffer *bytes.Buffer
|
||||
SenseLength uint32
|
||||
ITNexus *ITNexus
|
||||
ITNexusLuInfo *ITNexusLuInfo
|
||||
}
|
||||
type ITNexus struct {
|
||||
ID uint64
|
||||
Ctime uint64
|
||||
Commands []SCSICommand
|
||||
Target *SCSITarget
|
||||
Host int
|
||||
Info string
|
||||
}
|
||||
|
||||
type ITNexusLuInfo struct {
|
||||
Lu *SCSILu
|
||||
ID uint64
|
||||
Prevent int
|
||||
}
|
||||
|
||||
type SCSITarget struct {
|
||||
Name string
|
||||
TID int
|
||||
LID int
|
||||
State SCSITargetState
|
||||
Devices []SCSILu
|
||||
ITNexus []ITNexus
|
||||
|
||||
SCSITargetDriver interface{}
|
||||
}
|
||||
|
||||
type SCSITargetDriverState int
|
||||
|
||||
const (
|
||||
// just registered
|
||||
SCSI_DRIVER_REGD = iota
|
||||
// initialized ok
|
||||
SCSI_DRIVER_INIT
|
||||
// failed to initialize
|
||||
SCSI_DRIVER_ERR
|
||||
// exited
|
||||
SCSI_DRIVER_EXIT
|
||||
)
|
||||
|
||||
type SCSITargetDriverCommon struct {
|
||||
Name string
|
||||
State SCSITargetDriverState
|
||||
DefaultBST string
|
||||
}
|
||||
|
||||
type SCSILuPhyAttribute struct {
|
||||
SCSIID string
|
||||
SCSISN string
|
||||
NumID uint64
|
||||
VendorID string
|
||||
ProductID string
|
||||
ProductRev string
|
||||
VersionDesction []uint16
|
||||
// Peripheral device type
|
||||
DeviceType uint
|
||||
// Peripheral Qualifier
|
||||
Qualifier bool
|
||||
// Removable media
|
||||
Removable bool
|
||||
// Read Only media
|
||||
Readonly bool
|
||||
// Software Write Protect
|
||||
SWP bool
|
||||
// Use thin-provisioning for this LUN
|
||||
Thinprovisioning bool
|
||||
// Logical Unit online
|
||||
Online bool
|
||||
// Descrptor format sense data supported
|
||||
SenseFormat bool
|
||||
// Logical blocks per physical block exponent
|
||||
Lbppbe int
|
||||
// Do not update it automatically when the backing file changes
|
||||
NoLbppbe int
|
||||
// Lowest aligned LBA
|
||||
LowestAlignedLBA int
|
||||
}
|
||||
|
||||
var (
|
||||
DefaultBlockShift int = 9
|
||||
DefaultSenseBufferSize int = 252
|
||||
)
|
||||
|
||||
var (
|
||||
SAM_STAT_GOOD byte = 0x00
|
||||
SAM_STAT_CHECK_CONDITION byte = 0x02
|
||||
SAM_STAT_CONDITION_MET byte = 0x04
|
||||
SAM_STAT_BUSY byte = 0x08
|
||||
SAM_STAT_INTERMEDIATE byte = 0x10
|
||||
SAM_STAT_INTERMEDIATE_CONDITION_MET byte = 0x14
|
||||
SAM_STAT_RESERVATION_CONFLICT byte = 0x18
|
||||
SAM_STAT_COMMAND_TERMINATED byte = 0x22
|
||||
SAM_STAT_TASK_SET_FULL byte = 0x28
|
||||
SAM_STAT_ACA_ACTIVE byte = 0x30
|
||||
SAM_STAT_TASK_ABORTED byte = 0x40
|
||||
)
|
||||
|
||||
type SAMStat struct {
|
||||
Stat byte
|
||||
Err error
|
||||
}
|
||||
|
||||
var (
|
||||
SAMStatGood = SAMStat{SAM_STAT_GOOD, nil}
|
||||
SAMStatCheckCondition = SAMStat{SAM_STAT_CHECK_CONDITION, errors.New("check condition")}
|
||||
SAMStatConditionMet = SAMStat{SAM_STAT_CONDITION_MET, errors.New("condition met")}
|
||||
SAMStatBusy = SAMStat{SAM_STAT_BUSY, errors.New("busy")}
|
||||
SAMStatIntermediate = SAMStat{SAM_STAT_INTERMEDIATE, errors.New("intermediate")}
|
||||
SAMStatIntermediateConditionMet = SAMStat{SAM_STAT_INTERMEDIATE_CONDITION_MET, errors.New("intermediate condition met")}
|
||||
SAMStatReservationConflict = SAMStat{SAM_STAT_RESERVATION_CONFLICT, errors.New("reservation conflict")}
|
||||
SAMStatCommandTerminated = SAMStat{SAM_STAT_COMMAND_TERMINATED, errors.New("command terminated")}
|
||||
SAMStatTaskSetFull = SAMStat{SAM_STAT_TASK_SET_FULL, errors.New("task set full")}
|
||||
SAMStatAcaActive = SAMStat{SAM_STAT_ACA_ACTIVE, errors.New("aca active")}
|
||||
SAMStatTaskAborted = SAMStat{SAM_STAT_TASK_ABORTED, errors.New("task aborted")}
|
||||
)
|
||||
|
||||
type SCSIDeviceType byte
|
||||
|
||||
var (
|
||||
TYPE_DISK SCSIDeviceType = 0x00
|
||||
TYPE_TAPE SCSIDeviceType = 0x01
|
||||
TYPE_PRINTER SCSIDeviceType = 0x02
|
||||
TYPE_PROCESSOR SCSIDeviceType = 0x03
|
||||
TYPE_WORM SCSIDeviceType = 0x04
|
||||
TYPE_MMC SCSIDeviceType = 0x05
|
||||
TYPE_SCANNER SCSIDeviceType = 0x06
|
||||
TYPE_MOD SCSIDeviceType = 0x07
|
||||
|
||||
TYPE_MEDIUM_CHANGER SCSIDeviceType = 0x08
|
||||
TYPE_COMM SCSIDeviceType = 0x09
|
||||
TYPE_RAID SCSIDeviceType = 0x0c
|
||||
TYPE_ENCLOSURE SCSIDeviceType = 0x0d
|
||||
TYPE_RBC SCSIDeviceType = 0x0e
|
||||
TYPE_OSD SCSIDeviceType = 0x11
|
||||
TYPE_NO_LUN SCSIDeviceType = 0x7f
|
||||
|
||||
TYPE_PT SCSIDeviceType = 0xff
|
||||
)
|
||||
|
||||
type SCSILu struct {
|
||||
FD int
|
||||
Address uint64
|
||||
Size uint64
|
||||
Lun uint64
|
||||
Path string
|
||||
BsoFlags int
|
||||
BlockShift uint
|
||||
ReserveID uint64
|
||||
Attrs SCSILuPhyAttribute
|
||||
}
|
||||
70
pkg/port/interfaces.go
Normal file
70
pkg/port/interfaces.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package port
|
||||
|
||||
import (
|
||||
"github.com/gostor/gotgt/pkg/api"
|
||||
"github.com/gostor/gotgt/pkg/port/iscsit"
|
||||
)
|
||||
|
||||
type SCSITargetDriver interface {
|
||||
Init() error
|
||||
Exit() error
|
||||
|
||||
CreateTarget(target *api.SCSITarget) error
|
||||
DestroyTarget(target *api.SCSITarget) error
|
||||
CreatePortal(name string) error
|
||||
DestroyPortal(name string) error
|
||||
CreateLu(lu *api.SCSILu) error
|
||||
GetLu(lun uint8) (uint64, error)
|
||||
|
||||
ProcessCommand(buf []byte) ([]byte, error)
|
||||
CommandNotify(nid uint64, result int, cmd *api.SCSICommand) error
|
||||
}
|
||||
|
||||
type fakeSCSITargetDriver struct {
|
||||
api.SCSITargetDriverCommon
|
||||
}
|
||||
|
||||
func (fake *fakeSCSITargetDriver) Init() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fake *fakeSCSITargetDriver) Exit() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fake *fakeSCSITargetDriver) CreateTarget(target *api.SCSITarget) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fake *fakeSCSITargetDriver) DestroyTarget(target *api.SCSITarget) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fake *fakeSCSITargetDriver) CreatePortal(name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fake *fakeSCSITargetDriver) DestroyPortal(name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fake *fakeSCSITargetDriver) CreateLu(lu *api.SCSILu) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fake *fakeSCSITargetDriver) GetLun(lun uint8) (uint64, error) {
|
||||
return 0, nil
|
||||
}
|
||||
func (fake *fakeSCSITargetDriver) CommandNotify(nid uint64, result int, cmd *api.SCSICommand) error {
|
||||
return nil
|
||||
}
|
||||
func (fake *fakeSCSITargetDriver) ProcessCommand(buf []byte) ([]byte, error) {
|
||||
return []byte(""), nil
|
||||
}
|
||||
|
||||
func NewTargetDriver(driver string, tgt *api.SCSITarget) SCSITargetDriver {
|
||||
if driver == "iscsi" {
|
||||
return iscsit.NewISCSITarget(tgt)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,26 +1,8 @@
|
||||
/*
|
||||
Copyright 2015 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 packet implements the iSCSI PDU packet format as specified in
|
||||
// rfc7143 section 11.
|
||||
package iscsit
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -70,15 +52,7 @@ var opCodeMap = map[OpCode]string{
|
||||
OpReject: "Reject",
|
||||
}
|
||||
|
||||
func (c OpCode) String() string {
|
||||
s := opCodeMap[c]
|
||||
if s == "" {
|
||||
s = fmt.Sprintf("Unknown Code: %x", int(c))
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
type Message struct {
|
||||
type ISCSICommand struct {
|
||||
OpCode OpCode
|
||||
RawHeader []byte
|
||||
DataLen int
|
||||
@@ -109,8 +83,8 @@ type Message struct {
|
||||
// SCSI commands
|
||||
ExpectedDataLen uint32
|
||||
CDB []byte
|
||||
Status Status
|
||||
SCSIResponse Response
|
||||
Status byte
|
||||
SCSIResponse byte
|
||||
|
||||
// Data-In
|
||||
HasStatus bool
|
||||
@@ -118,23 +92,23 @@ type Message struct {
|
||||
BufferOffset uint32
|
||||
}
|
||||
|
||||
func (m *Message) Bytes() []byte {
|
||||
switch m.OpCode {
|
||||
func (cmd *ISCSICommand) Bytes() []byte {
|
||||
switch cmd.OpCode {
|
||||
case OpLoginResp:
|
||||
return m.loginRespBytes()
|
||||
return cmd.loginRespBytes()
|
||||
case OpLogoutResp:
|
||||
return m.logoutRespBytes()
|
||||
return cmd.logoutRespBytes()
|
||||
case OpSCSIResp:
|
||||
return m.scsiCmdRespBytes()
|
||||
return cmd.scsiCmdRespBytes()
|
||||
case OpSCSIIn:
|
||||
return m.dataInBytes()
|
||||
return cmd.dataInBytes()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Message) String() string {
|
||||
func (m *ISCSICommand) String() string {
|
||||
var s []string
|
||||
s = append(s, fmt.Sprintf("Op: %v", m.OpCode))
|
||||
s = append(s, fmt.Sprintf("Op: %v", opCodeMap[m.OpCode]))
|
||||
s = append(s, fmt.Sprintf("Final = %v", m.Final))
|
||||
s = append(s, fmt.Sprintf("Immediate = %v", m.Immediate))
|
||||
s = append(s, fmt.Sprintf("Data Segment Length = %d", m.DataLen))
|
||||
@@ -171,37 +145,6 @@ func (m *Message) String() string {
|
||||
return strings.Join(s, "\n")
|
||||
}
|
||||
|
||||
// Response composes a reply to the given message with the appropriate bits set.
|
||||
func (m *Message) Response(r *Message) {
|
||||
r.TaskTag = m.TaskTag
|
||||
r.ConnID = m.ConnID
|
||||
r.ISID = m.ISID
|
||||
}
|
||||
|
||||
func Next(r io.Reader) (*Message, error) {
|
||||
buf := make([]byte, 48) // TODO: sync.Pool
|
||||
if _, err := io.ReadFull(r, buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m, err := parseHeader(buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m.RawHeader = buf
|
||||
if m.DataLen > 0 {
|
||||
dl := m.DataLen
|
||||
for dl%4 > 0 {
|
||||
dl++
|
||||
}
|
||||
data := make([]byte, dl)
|
||||
if _, err := io.ReadFull(r, data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m.RawData = data[:m.DataLen]
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// parseUint parses the given slice as a network-byte-ordered integer. If
|
||||
// there are more than 8 bytes in data, it overflows.
|
||||
func ParseUint(data []byte) uint64 {
|
||||
@@ -220,13 +163,12 @@ func MarshalUint64(i uint64) []byte {
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func parseHeader(data []byte) (*Message, error) {
|
||||
func parseHeader(data []byte) (*ISCSICommand, error) {
|
||||
if len(data) != 48 {
|
||||
return nil, fmt.Errorf("garbled header")
|
||||
}
|
||||
// TODO: sync.Pool
|
||||
m := &Message{}
|
||||
m := &ISCSICommand{}
|
||||
m.Immediate = 0x40&data[0] == 0x40
|
||||
m.OpCode = OpCode(data[0] & 0x3f)
|
||||
m.Final = 0x80&data[1] == 0x80
|
||||
@@ -274,3 +216,197 @@ func parseHeader(data []byte) (*Message, error) {
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (m *ISCSICommand) scsiCmdRespBytes() []byte {
|
||||
// rfc7143 11.4
|
||||
buf := &bytes.Buffer{}
|
||||
buf.WriteByte(byte(OpSCSIResp))
|
||||
buf.WriteByte(0x80) // 11.4.1 = wtf
|
||||
buf.WriteByte(byte(m.SCSIResponse))
|
||||
buf.WriteByte(byte(m.Status))
|
||||
|
||||
// Skip through to byte 16
|
||||
for i := 0; i < 3*4; i++ {
|
||||
buf.WriteByte(0x00)
|
||||
}
|
||||
buf.Write(MarshalUint64(uint64(m.TaskTag))[4:])
|
||||
for i := 0; i < 4; i++ {
|
||||
buf.WriteByte(0x00)
|
||||
}
|
||||
buf.Write(MarshalUint64(uint64(m.StatSN))[4:])
|
||||
buf.Write(MarshalUint64(uint64(m.ExpCmdSN))[4:])
|
||||
buf.Write(MarshalUint64(uint64(m.MaxCmdSN))[4:])
|
||||
for i := 0; i < 3*4; i++ {
|
||||
buf.WriteByte(0x00)
|
||||
}
|
||||
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
func (m *ISCSICommand) dataInBytes() []byte {
|
||||
// rfc7143 11.7
|
||||
buf := &bytes.Buffer{}
|
||||
buf.WriteByte(byte(OpSCSIIn))
|
||||
var b byte
|
||||
b = 0x80
|
||||
if m.HasStatus {
|
||||
b |= 0x01
|
||||
}
|
||||
buf.WriteByte(b)
|
||||
buf.WriteByte(0x00)
|
||||
if m.HasStatus {
|
||||
b = byte(m.Status)
|
||||
}
|
||||
buf.WriteByte(b)
|
||||
|
||||
buf.WriteByte(0x00) // 4
|
||||
buf.Write(MarshalUint64(uint64(len(m.RawData)))[5:]) // 5-8
|
||||
buf.WriteByte(0x00)
|
||||
buf.WriteByte(byte(m.LUN))
|
||||
// Skip through to byte 16
|
||||
for i := 0; i < 6; i++ {
|
||||
buf.WriteByte(0x00)
|
||||
}
|
||||
buf.Write(MarshalUint64(uint64(m.TaskTag))[4:])
|
||||
for i := 0; i < 4; i++ {
|
||||
// 11.7.4
|
||||
buf.WriteByte(0xff)
|
||||
}
|
||||
buf.Write(MarshalUint64(uint64(m.StatSN))[4:])
|
||||
buf.Write(MarshalUint64(uint64(m.ExpCmdSN))[4:])
|
||||
buf.Write(MarshalUint64(uint64(m.MaxCmdSN))[4:])
|
||||
buf.Write(MarshalUint64(uint64(m.DataSN))[4:])
|
||||
buf.Write(MarshalUint64(uint64(m.BufferOffset))[4:])
|
||||
for i := 0; i < 4; i++ {
|
||||
buf.WriteByte(0x00)
|
||||
}
|
||||
buf.Write(m.RawData)
|
||||
dl := len(m.RawData)
|
||||
for dl%4 > 0 {
|
||||
dl++
|
||||
buf.WriteByte(0x00)
|
||||
}
|
||||
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
type InquiryData struct {
|
||||
PeripheralQualifier int
|
||||
PeripheralType int
|
||||
Removable bool
|
||||
Version int
|
||||
SupportsACA bool
|
||||
Hierarchical bool
|
||||
SupportsSCC bool
|
||||
HasACC bool
|
||||
TargetGroupSupport int
|
||||
ThirdPartyCopy bool
|
||||
Protect bool
|
||||
EnclosureServices bool
|
||||
Multiport bool
|
||||
MediaChanger bool
|
||||
Vendor [8]byte
|
||||
Product [16]byte
|
||||
RevisionLevel [4]byte
|
||||
SerialNumber uint64
|
||||
}
|
||||
|
||||
func (id *InquiryData) bytes() []byte {
|
||||
buf := &bytes.Buffer{}
|
||||
var b byte
|
||||
b = (uint8(id.PeripheralQualifier) << 5) & 0xe0
|
||||
b |= uint8(id.PeripheralType) & 0x1f
|
||||
buf.WriteByte(b)
|
||||
b = 0
|
||||
if id.Removable {
|
||||
b = 0x80
|
||||
}
|
||||
buf.WriteByte(b)
|
||||
buf.WriteByte(byte(id.Version))
|
||||
b = 0x02
|
||||
if id.SupportsACA {
|
||||
b |= 0x20
|
||||
}
|
||||
if id.Hierarchical {
|
||||
b |= 0x10
|
||||
}
|
||||
buf.WriteByte(b)
|
||||
buf.WriteByte(0x00)
|
||||
// byte 5
|
||||
b = 0
|
||||
if id.SupportsSCC {
|
||||
b |= 0x80
|
||||
}
|
||||
if id.HasACC {
|
||||
b |= 0x40
|
||||
}
|
||||
b |= byte(id.TargetGroupSupport) << 4 & 0x30
|
||||
if id.ThirdPartyCopy {
|
||||
b |= 0x08
|
||||
}
|
||||
if id.Protect {
|
||||
b |= 0x01
|
||||
}
|
||||
buf.WriteByte(b)
|
||||
// byte 6
|
||||
b = 0
|
||||
if id.EnclosureServices {
|
||||
b |= 0x40
|
||||
}
|
||||
if id.Multiport {
|
||||
b |= 0x10
|
||||
}
|
||||
if id.MediaChanger {
|
||||
b |= 0x08
|
||||
}
|
||||
buf.WriteByte(b)
|
||||
buf.WriteByte(0x02)
|
||||
buf.Write(id.Vendor[:])
|
||||
buf.Write(id.Product[:])
|
||||
buf.Write(id.RevisionLevel[:])
|
||||
buf.Write(MarshalUint64(id.SerialNumber))
|
||||
for i := 0; i < 12; i++ {
|
||||
buf.WriteByte(0x00)
|
||||
}
|
||||
data := buf.Bytes()
|
||||
data[4] = byte(len(data) - 4)
|
||||
return data
|
||||
}
|
||||
|
||||
type Capacity struct {
|
||||
LBA uint64
|
||||
Blocksize uint32
|
||||
ProtectionType uint8
|
||||
PIExponent uint8
|
||||
LogicalExponent uint8
|
||||
ThinProvisioned bool
|
||||
ThinProvReturnsZeros bool
|
||||
LowestLBA uint16
|
||||
}
|
||||
|
||||
func (c *Capacity) bytes() []byte {
|
||||
// table 111
|
||||
// http://www.seagate.com/staticfiles/support/disc/manuals/Interface%20manuals/100293068c.pdf
|
||||
buf := &bytes.Buffer{}
|
||||
buf.Write(MarshalUint64(c.LBA))
|
||||
buf.Write(MarshalUint64(uint64(c.Blocksize))[4:])
|
||||
var b byte
|
||||
if c.ProtectionType > 0 {
|
||||
b |= 0x01
|
||||
b |= c.ProtectionType << 1
|
||||
b &= 0x0f
|
||||
}
|
||||
buf.WriteByte(b)
|
||||
b = c.PIExponent << 4
|
||||
b |= c.LogicalExponent
|
||||
buf.WriteByte(b)
|
||||
lowLBA := MarshalUint64(uint64(c.LowestLBA))[6:]
|
||||
lowLBA[0] &= 0x3f
|
||||
if c.ThinProvisioned {
|
||||
lowLBA[0] &= 0x80
|
||||
}
|
||||
if c.ThinProvReturnsZeros {
|
||||
lowLBA[0] &= 0x40
|
||||
}
|
||||
return buf.Bytes()
|
||||
}
|
||||
@@ -17,6 +17,11 @@ limitations under the License.
|
||||
// iSCSI Target Driver
|
||||
package iscsit
|
||||
|
||||
import (
|
||||
"github.com/gostor/gotgt/pkg/api"
|
||||
"github.com/gostor/gotgt/pkg/util"
|
||||
)
|
||||
|
||||
type ISCSIDiscoveryMethod string
|
||||
|
||||
var (
|
||||
@@ -33,9 +38,11 @@ type ISCSIRedirectInfo struct {
|
||||
}
|
||||
|
||||
type ISCSITarget struct {
|
||||
*api.SCSITarget
|
||||
api.SCSITargetDriverCommon
|
||||
|
||||
Sessions []*ISCSISession
|
||||
SessionParam []ISCSISessionParam
|
||||
TID int
|
||||
Alias string
|
||||
MaxSessions int
|
||||
RedirectInfo ISCSIRedirectInfo
|
||||
@@ -44,41 +51,128 @@ type ISCSITarget struct {
|
||||
NopCount int
|
||||
}
|
||||
|
||||
type ISCSITargetDriver struct {
|
||||
SCSITargetDriver
|
||||
func NewISCSITarget(target *api.SCSITarget) *ISCSITarget {
|
||||
return &ISCSITarget{
|
||||
SCSITarget: target,
|
||||
}
|
||||
}
|
||||
|
||||
func (tgt *ISCSITargetDriver) Init() error {
|
||||
func (tgt *ISCSITarget) Init() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tgt *ISCSITargetDriver) Exit() error {
|
||||
func (tgt *ISCSITarget) Exit() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tgt *ISCSITargetDriver) CreateTarget(target *SCSITarget) error {
|
||||
func (tgt *ISCSITarget) CreateTarget(target *api.SCSITarget) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tgt *ISCSITargetDriver) DestroyTarget(target *SCSITarget) error {
|
||||
func (tgt *ISCSITarget) DestroyTarget(target *api.SCSITarget) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tgt *ISCSITargetDriver) CreatePortal(name string) error {
|
||||
func (tgt *ISCSITarget) CreatePortal(name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tgt *ISCSITargetDriver) DestroyPortal(name string) error {
|
||||
func (tgt *ISCSITarget) DestroyPortal(name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tgt *ISCSITargetDriver) CreateLu(lu *SCSILu) error {
|
||||
func (tgt *ISCSITarget) CreateLu(lu *api.SCSILu) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tgt *ISCSITargetDriver) GetLun(lun uint8) (uint64, error) {
|
||||
func (tgt *ISCSITarget) GetLu(lun uint8) (uint64, error) {
|
||||
return 0, nil
|
||||
}
|
||||
func (tgt *ISCSITargetDriver) CommandNotify(nid uint64, result int, cmd *SCSICommand) error {
|
||||
func (tgt *ISCSITarget) CommandNotify(nid uint64, result int, cmd *api.SCSICommand) error {
|
||||
return nil
|
||||
}
|
||||
func (tgt *ISCSITarget) ProcessCommand(buf []byte) ([]byte, error) {
|
||||
b := make([]byte, 48) // TODO: sync.Pool
|
||||
b = buf[0:48]
|
||||
m, err := parseHeader(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m.RawHeader = b
|
||||
if m.DataLen > 0 {
|
||||
m.RawData = buf[48:m.DataLen]
|
||||
}
|
||||
resp := &ISCSICommand{}
|
||||
switch m.OpCode {
|
||||
case OpLoginReq:
|
||||
resp = &ISCSICommand{
|
||||
OpCode: OpLoginResp,
|
||||
Transit: true,
|
||||
NSG: FullFeaturePhase,
|
||||
StatSN: m.ExpStatSN,
|
||||
TaskTag: m.TaskTag,
|
||||
ExpCmdSN: m.CmdSN,
|
||||
MaxCmdSN: m.CmdSN,
|
||||
RawData: util.MarshalKVText(map[string]string{
|
||||
"HeaderDigest": "None",
|
||||
"DataDigest": "None",
|
||||
}),
|
||||
}
|
||||
break
|
||||
case OpSCSICmd:
|
||||
resp = &ISCSICommand{
|
||||
OpCode: OpSCSIResp,
|
||||
Final: true,
|
||||
StatSN: m.ExpStatSN,
|
||||
TaskTag: m.TaskTag,
|
||||
ExpCmdSN: m.CmdSN + 1,
|
||||
MaxCmdSN: m.CmdSN + 10,
|
||||
}
|
||||
switch api.SCSICommandType(m.CDB[0]) {
|
||||
case api.TEST_UNIT_READY:
|
||||
// test unit ready
|
||||
resp.Status = api.SAM_STAT_GOOD
|
||||
resp.SCSIResponse = 0x01
|
||||
break
|
||||
case api.READ_CAPACITY:
|
||||
resp.OpCode = OpSCSIIn
|
||||
resp.HasStatus = true
|
||||
var data []byte
|
||||
data = append(data, MarshalUint64(uint64(0))[4:]...)
|
||||
data = append(data, MarshalUint64(uint64(0))[4:]...)
|
||||
resp.RawData = data
|
||||
break
|
||||
case api.SERVICE_ACTION_IN:
|
||||
resp.OpCode = OpSCSIIn
|
||||
resp.HasStatus = true
|
||||
sa := m.CDB[1] & 0x1f
|
||||
switch sa {
|
||||
case 0x10:
|
||||
c := &Capacity{}
|
||||
resp.RawData = c.bytes()
|
||||
}
|
||||
break
|
||||
case api.INQUIRY:
|
||||
resp.OpCode = OpSCSIIn
|
||||
resp.HasStatus = true
|
||||
alloc := int(ParseUint(m.CDB[3:5]))
|
||||
inq := &InquiryData{
|
||||
Vendor: [8]byte{'1', '1', 'c', 'a', 'n', 's'},
|
||||
Product: [16]byte{'c', 'o', 'f', 'f', 'e', 'e'},
|
||||
RevisionLevel: [4]byte{'1', '.', '0'},
|
||||
SerialNumber: 52,
|
||||
}
|
||||
|
||||
if len(inq.bytes()) >= alloc {
|
||||
resp.RawData = inq.bytes()[:alloc]
|
||||
} else {
|
||||
resp.RawData = inq.bytes()
|
||||
}
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
b1 := resp.Bytes()
|
||||
return b1, nil
|
||||
}
|
||||
|
||||
@@ -1,24 +1,8 @@
|
||||
/*
|
||||
Copyright 2015 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 iscsit
|
||||
|
||||
import "bytes"
|
||||
|
||||
func (m *Message) loginRespBytes() []byte {
|
||||
func (m *ISCSICommand) loginRespBytes() []byte {
|
||||
// rfc7143 11.13
|
||||
buf := &bytes.Buffer{}
|
||||
// byte 0
|
||||
|
||||
@@ -1,24 +1,8 @@
|
||||
/*
|
||||
Copyright 2015 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 iscsit
|
||||
|
||||
import "bytes"
|
||||
|
||||
func (m *Message) logoutRespBytes() []byte {
|
||||
func (m *ISCSICommand) logoutRespBytes() []byte {
|
||||
buf := &bytes.Buffer{}
|
||||
buf.WriteByte(byte(OpLogoutResp))
|
||||
buf.WriteByte(0x80)
|
||||
|
||||
@@ -42,6 +42,9 @@ type ISCSISession struct {
|
||||
Rdma int
|
||||
}
|
||||
|
||||
type ISCSIHeader struct {
|
||||
}
|
||||
|
||||
type ISCSIPdu struct {
|
||||
Bhs ISCSIHeader
|
||||
AhsSize uint
|
||||
@@ -78,7 +81,7 @@ func NewISCSISession() (*ISCSISession, error) {
|
||||
tsih += uint16(b[0]) << 8
|
||||
tsih += uint16(b[1])
|
||||
|
||||
return &Session{
|
||||
return &ISCSISession{
|
||||
Tsih: tsih,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -16,7 +16,11 @@ limitations under the License.
|
||||
|
||||
package scsi
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gostor/gotgt/pkg/api"
|
||||
)
|
||||
|
||||
type BaseBackingStore struct {
|
||||
Name string
|
||||
@@ -25,11 +29,11 @@ type BaseBackingStore struct {
|
||||
}
|
||||
|
||||
type BackingStore interface {
|
||||
Open(dev *SCSILu, path string, fd *int, size *uint64) error
|
||||
Close(dev *SCSILu) error
|
||||
Init(dev *SCSILu, Opts string) error
|
||||
Exit(dev *SCSILu) error
|
||||
CommandSubmit(cmd *SCSICommand) error
|
||||
Open(dev *api.SCSILu, path string, fd *int, size *uint64) error
|
||||
Close(dev *api.SCSILu) error
|
||||
Init(dev *api.SCSILu, Opts string) error
|
||||
Exit(dev *api.SCSILu) error
|
||||
CommandSubmit(cmd *api.SCSICommand) error
|
||||
}
|
||||
|
||||
type BackingStoreFunc func() (BackingStore, error)
|
||||
@@ -55,22 +59,22 @@ type fakeBackingStore struct {
|
||||
BaseBackingStore
|
||||
}
|
||||
|
||||
func (fake *fakeBackingStore) Open(dev *SCSILu, path string, fd *int, size *uint64) error {
|
||||
func (fake *fakeBackingStore) Open(dev *api.SCSILu, path string, fd *int, size *uint64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fake *fakeBackingStore) Close(dev *SCSILu) error {
|
||||
func (fake *fakeBackingStore) Close(dev *api.SCSILu) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fake *fakeBackingStore) Init(dev *SCSILu, Opts string) error {
|
||||
func (fake *fakeBackingStore) Init(dev *api.SCSILu, Opts string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fake *fakeBackingStore) Exit(dev *SCSILu) error {
|
||||
func (fake *fakeBackingStore) Exit(dev *api.SCSILu) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fake *fakeBackingStore) CommandSubmit(cmd *SCSICommand) error {
|
||||
func (fake *fakeBackingStore) CommandSubmit(cmd *api.SCSICommand) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -16,7 +16,11 @@ limitations under the License.
|
||||
|
||||
package backingstore
|
||||
|
||||
import "github.com/gostor/gotgt/pkg/scsi"
|
||||
import (
|
||||
"github.com/gostor/gotgt/pkg/scsi"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
func init() {
|
||||
scsi.RegisterBackingStore("null", new)
|
||||
@@ -35,6 +39,7 @@ func new() (scsi.BackingStore, error) {
|
||||
}
|
||||
|
||||
func (bs *NullBackingStore) Open(dev *SCSILu, path string, fd *int, size *uint64) error {
|
||||
glog.V(1).Infof("NULL backing store open, size: %d", size)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -51,5 +56,6 @@ func (bs *NullBackingStore) Exit(dev *SCSILu) error {
|
||||
}
|
||||
|
||||
func (bs *NullBackingStore) CommandSubmit(cmd *SCSICommand) error {
|
||||
cmd.Result = SAM_STAT_GOOD
|
||||
return nil
|
||||
}
|
||||
|
||||
147
pkg/scsi/cmd.go
147
pkg/scsi/cmd.go
@@ -16,113 +16,6 @@ limitations under the License.
|
||||
|
||||
package scsi
|
||||
|
||||
import "bytes"
|
||||
|
||||
type SCSICommandType byte
|
||||
|
||||
var (
|
||||
TEST_UNIT_READY SCSICommandType = 0x00
|
||||
REZERO_UNIT SCSICommandType = 0x01
|
||||
REQUEST_SENSE SCSICommandType = 0x03
|
||||
FORMAT_UNIT SCSICommandType = 0x04
|
||||
READ_BLOCK_LIMITS SCSICommandType = 0x05
|
||||
REASSIGN_BLOCKS SCSICommandType = 0x07
|
||||
INITIALIZE_ELEMENT_STATUS SCSICommandType = 0x07
|
||||
READ_6 SCSICommandType = 0x08
|
||||
WRITE_6 SCSICommandType = 0x0a
|
||||
SEEK_6 SCSICommandType = 0x0b
|
||||
READ_REVERSE SCSICommandType = 0x0f
|
||||
WRITE_FILEMARKS SCSICommandType = 0x10
|
||||
SPACE SCSICommandType = 0x11
|
||||
INQUIRY SCSICommandType = 0x12
|
||||
RECOVER_BUFFERED_DATA SCSICommandType = 0x14
|
||||
MODE_SELECT SCSICommandType = 0x15
|
||||
RESERVE SCSICommandType = 0x16
|
||||
RELEASE SCSICommandType = 0x17
|
||||
COPY SCSICommandType = 0x18
|
||||
ERASE SCSICommandType = 0x19
|
||||
MODE_SENSE SCSICommandType = 0x1a
|
||||
START_STOP SCSICommandType = 0x1b
|
||||
RECEIVE_DIAGNOSTIC SCSICommandType = 0x1c
|
||||
SEND_DIAGNOSTIC SCSICommandType = 0x1d
|
||||
ALLOW_MEDIUM_REMOVAL SCSICommandType = 0x1e
|
||||
|
||||
SET_WINDOW SCSICommandType = 0x24
|
||||
READ_CAPACITY SCSICommandType = 0x25
|
||||
READ_10 SCSICommandType = 0x28
|
||||
WRITE_10 SCSICommandType = 0x2a
|
||||
SEEK_10 SCSICommandType = 0x2b
|
||||
POSITION_TO_ELEMENT SCSICommandType = 0x2b
|
||||
WRITE_VERIFY SCSICommandType = 0x2e
|
||||
VERIFY_10 SCSICommandType = 0x2f
|
||||
SEARCH_HIGH SCSICommandType = 0x30
|
||||
SEARCH_EQUAL SCSICommandType = 0x31
|
||||
SEARCH_LOW SCSICommandType = 0x32
|
||||
SET_LIMITS SCSICommandType = 0x33
|
||||
PRE_FETCH_10 SCSICommandType = 0x34
|
||||
READ_POSITION SCSICommandType = 0x34
|
||||
SYNCHRONIZE_CACHE SCSICommandType = 0x35
|
||||
LOCK_UNLOCK_CACHE SCSICommandType = 0x36
|
||||
READ_DEFECT_DATA SCSICommandType = 0x37
|
||||
INITIALIZE_ELEMENT_STATUS_WITH_RANGE SCSICommandType = 0x37
|
||||
MEDIUM_SCAN SCSICommandType = 0x38
|
||||
COMPARE SCSICommandType = 0x39
|
||||
COPY_VERIFY SCSICommandType = 0x3a
|
||||
WRITE_BUFFER SCSICommandType = 0x3b
|
||||
READ_BUFFER SCSICommandType = 0x3c
|
||||
UPDATE_BLOCK SCSICommandType = 0x3d
|
||||
READ_LONG SCSICommandType = 0x3e
|
||||
WRITE_LONG SCSICommandType = 0x3f
|
||||
CHANGE_DEFINITION SCSICommandType = 0x40
|
||||
WRITE_SAME SCSICommandType = 0x41
|
||||
UNMAP SCSICommandType = 0x42
|
||||
READ_TOC SCSICommandType = 0x43
|
||||
GET_CONFIGURATION SCSICommandType = 0x46
|
||||
LOG_SELECT SCSICommandType = 0x4c
|
||||
LOG_SENSE SCSICommandType = 0x4d
|
||||
READ_DISK_INFO SCSICommandType = 0x51
|
||||
READ_TRACK_INFO SCSICommandType = 0x52
|
||||
MODE_SELECT_10 SCSICommandType = 0x55
|
||||
RESERVE_10 SCSICommandType = 0x56
|
||||
RELEASE_10 SCSICommandType = 0x57
|
||||
MODE_SENSE_10 SCSICommandType = 0x5a
|
||||
CLOSE_TRACK SCSICommandType = 0x5b
|
||||
READ_BUFFER_CAP SCSICommandType = 0x5c
|
||||
PERSISTENT_RESERVE_IN SCSICommandType = 0x5e
|
||||
PERSISTENT_RESERVE_OUT SCSICommandType = 0x5f
|
||||
VARLEN_CDB SCSICommandType = 0x7f
|
||||
READ_16 SCSICommandType = 0x88
|
||||
COMPARE_AND_WRITE SCSICommandType = 0x89
|
||||
WRITE_16 SCSICommandType = 0x8a
|
||||
ORWRITE_16 SCSICommandType = 0x8b
|
||||
WRITE_VERIFY_16 SCSICommandType = 0x8e
|
||||
VERIFY_16 SCSICommandType = 0x8f
|
||||
PRE_FETCH_16 SCSICommandType = 0x90
|
||||
SYNCHRONIZE_CACHE_16 SCSICommandType = 0x91
|
||||
WRITE_SAME_16 SCSICommandType = 0x93
|
||||
SERVICE_ACTION_IN SCSICommandType = 0x9e
|
||||
SAI_READ_CAPACITY_16 SCSICommandType = 0x10
|
||||
SAI_GET_LBA_STATUS SCSICommandType = 0x12
|
||||
REPORT_LUNS SCSICommandType = 0xa0
|
||||
MAINT_PROTOCOL_IN SCSICommandType = 0xa3
|
||||
MOVE_MEDIUM SCSICommandType = 0xa5
|
||||
EXCHANGE_MEDIUM SCSICommandType = 0xa6
|
||||
READ_12 SCSICommandType = 0xa8
|
||||
WRITE_12 SCSICommandType = 0xaa
|
||||
GET_PERFORMACE SCSICommandType = 0xac
|
||||
READ_DVD_STRUCTURE SCSICommandType = 0xad
|
||||
WRITE_VERIFY_12 SCSICommandType = 0xae
|
||||
VERIFY_12 SCSICommandType = 0xaf
|
||||
SEARCH_HIGH_12 SCSICommandType = 0xb0
|
||||
SEARCH_EQUAL_12 SCSICommandType = 0xb1
|
||||
SEARCH_LOW_12 SCSICommandType = 0xb2
|
||||
READ_ELEMENT_STATUS SCSICommandType = 0xb8
|
||||
SEND_VOLUME_TAG SCSICommandType = 0xb6
|
||||
SET_STREAMING SCSICommandType = 0xb6
|
||||
SET_CD_SPEED SCSICommandType = 0xbb
|
||||
WRITE_LONG_2 SCSICommandType = 0xea
|
||||
)
|
||||
|
||||
type SCSIPRServiceAction byte
|
||||
type SCSIPRType byte
|
||||
|
||||
@@ -155,15 +48,6 @@ var (
|
||||
PR_TYPE_EXCLUSIVE_ACCESS_ALLREG SCSIPRType = 0x08
|
||||
)
|
||||
|
||||
type SCSIDataDirection int
|
||||
|
||||
const (
|
||||
SCSIDataNone = iota
|
||||
SCSIDataWrite
|
||||
SCSIDataRead
|
||||
SCSIDataBidirection
|
||||
)
|
||||
|
||||
const (
|
||||
CBD_GROUPID_0 = iota
|
||||
CBD_GROUPID_1
|
||||
@@ -186,37 +70,6 @@ const (
|
||||
CDB_GROUP7 = 0 /* vendor specific */
|
||||
)
|
||||
|
||||
type SCSIDataBuffer struct {
|
||||
Buffer *bytes.Buffer
|
||||
Length uint32
|
||||
TransferLength uint32
|
||||
Resid int32
|
||||
}
|
||||
|
||||
type SCSICommand struct {
|
||||
Target *SCSITarget
|
||||
DeviceID uint64
|
||||
Device *SCSILu
|
||||
State uint64
|
||||
Direction SCSIDataDirection
|
||||
InSDBBuffer SCSIDataBuffer
|
||||
OutSDBBuffer SCSIDataBuffer
|
||||
// Command ITN ID
|
||||
CommandITNID uint64
|
||||
Offset uint64
|
||||
TL uint32
|
||||
SCB *bytes.Buffer
|
||||
SCBLength int
|
||||
Lun []uint8
|
||||
Attribute int
|
||||
Tag uint64
|
||||
Result int
|
||||
SenseBuffer *bytes.Buffer
|
||||
SenseLength uint32
|
||||
ITNexus *ITNexus
|
||||
ITNexusLuInfo *ITNexusLuInfo
|
||||
}
|
||||
|
||||
func SCSICDBGroupID(opcode byte) byte {
|
||||
return ((opcode >> 5) & 0x7)
|
||||
}
|
||||
|
||||
@@ -16,76 +16,3 @@ limitations under the License.
|
||||
|
||||
// Target Driver Interface
|
||||
package scsi
|
||||
|
||||
type SCSITargetDriverState int
|
||||
|
||||
const (
|
||||
// just registered
|
||||
SCSI_DRIVER_REGD = iota
|
||||
// initialized ok
|
||||
SCSI_DRIVER_INIT
|
||||
// failed to initialize
|
||||
SCSI_DRIVER_ERR
|
||||
// exited
|
||||
SCSI_DRIVER_EXIT
|
||||
)
|
||||
|
||||
type SCSITargetDriver struct {
|
||||
Name string
|
||||
State SCSITargetDriverState
|
||||
DefaultBST string
|
||||
Targets []*SCSITarget
|
||||
}
|
||||
|
||||
type SCSITargetDriverOps interface {
|
||||
Init() error
|
||||
Exit() error
|
||||
|
||||
CreateTarget(target *SCSITarget) error
|
||||
DestroyTarget(target *SCSITarget) error
|
||||
CreatePortal(name string) error
|
||||
DestroyPortal(name string) error
|
||||
CreateLu(lu *SCSILu) error
|
||||
|
||||
GetLu(lun uint8) (uint64, error)
|
||||
CommandNotify(nid uint64, result int, cmd *SCSICommand) error
|
||||
}
|
||||
|
||||
type fakeSCSITargetDriver struct {
|
||||
SCSITargetDriver
|
||||
}
|
||||
|
||||
func (fake *fakeSCSITargetDriver) Init() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fake *fakeSCSITargetDriver) Exit() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fake *fakeSCSITargetDriver) CreateTarget(target *SCSITarget) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fake *fakeSCSITargetDriver) DestroyTarget(target *SCSITarget) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fake *fakeSCSITargetDriver) CreatePortal(name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fake *fakeSCSITargetDriver) DestroyPortal(name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fake *fakeSCSITargetDriver) CreateLu(lu *SCSILu) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fake *fakeSCSITargetDriver) GetLun(lun uint8) (uint64, error) {
|
||||
return 0, nil
|
||||
}
|
||||
func (fake *fakeSCSITargetDriver) CommandNotify(nid uint64, result int, cmd *SCSICommand) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -16,58 +16,22 @@ limitations under the License.
|
||||
|
||||
package scsi
|
||||
|
||||
type SCSILuPhyAttribute struct {
|
||||
SCSIID string
|
||||
SCSISN string
|
||||
NumID uint64
|
||||
VendorID string
|
||||
ProductID string
|
||||
ProductRev string
|
||||
VersionDesction []uint16
|
||||
// Peripheral device type
|
||||
DeviceType uint
|
||||
// Peripheral Qualifier
|
||||
Qualifier bool
|
||||
// Removable media
|
||||
Removable bool
|
||||
// Read Only media
|
||||
Readonly bool
|
||||
// Software Write Protect
|
||||
SWP bool
|
||||
// Use thin-provisioning for this LUN
|
||||
Thinprovisioning bool
|
||||
// Logical Unit online
|
||||
Online bool
|
||||
// Descrptor format sense data supported
|
||||
SenseFormat bool
|
||||
// Logical blocks per physical block exponent
|
||||
Lbppbe int
|
||||
// Do not update it automatically when the backing file changes
|
||||
NoLbppbe int
|
||||
// Lowest aligned LBA
|
||||
LowestAlignedLBA int
|
||||
}
|
||||
import "github.com/gostor/gotgt/pkg/api"
|
||||
|
||||
type SCSILuOps struct {
|
||||
*api.SCSILu
|
||||
|
||||
type SCSILu struct {
|
||||
FD int
|
||||
Address uint64
|
||||
Size uint64
|
||||
Lun uint64
|
||||
Path string
|
||||
BsoFlags int
|
||||
BlockShift uint
|
||||
ReserveID uint64
|
||||
DeviceProtocol SCSIDeviceProtocol
|
||||
Storage *BackingStore
|
||||
Target *SCSITarget
|
||||
Attrs SCSILuPhyAttribute
|
||||
Target *api.SCSITarget
|
||||
Attrs api.SCSILuPhyAttribute
|
||||
|
||||
// function handler for command performing and finishing
|
||||
PerformCommand CommandFunc
|
||||
FinishCommand func(*SCSITarget, *SCSICommand)
|
||||
FinishCommand func(*api.SCSITarget, *api.SCSICommand)
|
||||
}
|
||||
|
||||
func luPreventRemoval(lu *SCSILu) bool {
|
||||
func luPreventRemoval(lu *api.SCSILu) bool {
|
||||
// TODO
|
||||
return false
|
||||
}
|
||||
|
||||
173
pkg/scsi/sbc.go
173
pkg/scsi/sbc.go
@@ -17,96 +17,109 @@ limitations under the License.
|
||||
// SCSI block command processing
|
||||
package scsi
|
||||
|
||||
import "encoding/binary"
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/gostor/gotgt/pkg/api"
|
||||
)
|
||||
|
||||
const (
|
||||
PR_SPECIAL = (1 << 5)
|
||||
PR_WE_FA = (1 << 4)
|
||||
PR_EA_FA = (1 << 3)
|
||||
PR_RR_FR = (1 << 2)
|
||||
PR_WE_FN = (1 << 1)
|
||||
PR_EA_FN = (1 << 0)
|
||||
)
|
||||
|
||||
type SBCSCSIDeviceProtocol struct {
|
||||
BaseSCSIDeviceProtocol
|
||||
}
|
||||
|
||||
func (sbc *SBCSCSIDeviceProtocol) InitLu(lu *SCSILu) error {
|
||||
func (sbc *SBCSCSIDeviceProtocol) InitLu(lu *api.SCSILu) error {
|
||||
return nil
|
||||
}
|
||||
func (sbc *SBCSCSIDeviceProtocol) ExitLu(lu *SCSILu) error {
|
||||
func (sbc *SBCSCSIDeviceProtocol) ExitLu(lu *api.SCSILu) error {
|
||||
return nil
|
||||
}
|
||||
func (sbc *SBCSCSIDeviceProtocol) ConfigLu(lu *SCSILu) error {
|
||||
func (sbc *SBCSCSIDeviceProtocol) ConfigLu(lu *api.SCSILu) error {
|
||||
return nil
|
||||
}
|
||||
func (sbc *SBCSCSIDeviceProtocol) OnlineLu(lu *SCSILu) error {
|
||||
func (sbc *SBCSCSIDeviceProtocol) OnlineLu(lu *api.SCSILu) error {
|
||||
return nil
|
||||
}
|
||||
func (sbc *SBCSCSIDeviceProtocol) OfflineLu(lu *SCSILu) error {
|
||||
func (sbc *SBCSCSIDeviceProtocol) OfflineLu(lu *api.SCSILu) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewSBCDevice() SBCSCSIDeviceProtocol {
|
||||
var sbc = SBCSCSIDeviceProtocol{
|
||||
BaseSCSIDeviceProtocol{
|
||||
Type: TYPE_DISK,
|
||||
Type: api.TYPE_DISK,
|
||||
SCSIDeviceOps: make([]SCSIDeviceOperation, 256),
|
||||
},
|
||||
}
|
||||
for i := 0; i <= 256; i++ {
|
||||
sbc.SCSIDeviceOps = append(sbc.SCSIDeviceOps, NewSCSIDeviceOperation(SPCIllegalOp, nil, 0))
|
||||
}
|
||||
sbc.SCSIDeviceOps[TEST_UNIT_READY] = NewSCSIDeviceOperation(SPCTestUnit, nil, 0)
|
||||
sbc.SCSIDeviceOps[REQUEST_SENSE] = NewSCSIDeviceOperation(SPCRequestSense, nil, 0)
|
||||
sbc.SCSIDeviceOps[FORMAT_UNIT] = NewSCSIDeviceOperation(SBCFormatUnit, nil, 0)
|
||||
sbc.SCSIDeviceOps[READ_6] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN)
|
||||
sbc.SCSIDeviceOps[WRITE_6] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN|PR_WE_FA|PR_WE_FN)
|
||||
sbc.SCSIDeviceOps[INQUIRY] = NewSCSIDeviceOperation(SPCInquiry, nil, 0)
|
||||
sbc.SCSIDeviceOps[MODE_SELECT] = NewSCSIDeviceOperation(SBCModeSelect, nil, PR_WE_FA|PR_EA_FA|PR_WE_FN|PR_EA_FN)
|
||||
sbc.SCSIDeviceOps[RESERVE] = NewSCSIDeviceOperation(SBCReserve, nil, 0)
|
||||
sbc.SCSIDeviceOps[RELEASE] = NewSCSIDeviceOperation(SBCRelease, nil, 0)
|
||||
sbc.SCSIDeviceOps[api.TEST_UNIT_READY] = NewSCSIDeviceOperation(SPCTestUnit, nil, 0)
|
||||
sbc.SCSIDeviceOps[api.REQUEST_SENSE] = NewSCSIDeviceOperation(SPCRequestSense, nil, 0)
|
||||
sbc.SCSIDeviceOps[api.FORMAT_UNIT] = NewSCSIDeviceOperation(SBCFormatUnit, nil, 0)
|
||||
sbc.SCSIDeviceOps[api.READ_6] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN)
|
||||
sbc.SCSIDeviceOps[api.WRITE_6] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN|PR_WE_FA|PR_WE_FN)
|
||||
sbc.SCSIDeviceOps[api.INQUIRY] = NewSCSIDeviceOperation(SPCInquiry, nil, 0)
|
||||
sbc.SCSIDeviceOps[api.MODE_SELECT] = NewSCSIDeviceOperation(SBCModeSelect, nil, PR_WE_FA|PR_EA_FA|PR_WE_FN|PR_EA_FN)
|
||||
sbc.SCSIDeviceOps[api.RESERVE] = NewSCSIDeviceOperation(SBCReserve, nil, 0)
|
||||
sbc.SCSIDeviceOps[api.RELEASE] = NewSCSIDeviceOperation(SBCRelease, nil, 0)
|
||||
|
||||
sbc.SCSIDeviceOps[MODE_SENSE] = NewSCSIDeviceOperation(SBCModeSense, nil, PR_WE_FA|PR_EA_FA|PR_EA_FN|PR_WE_FN)
|
||||
sbc.SCSIDeviceOps[START_STOP] = NewSCSIDeviceOperation(SPCStartStop, nil, PR_SPECIAL)
|
||||
sbc.SCSIDeviceOps[SEND_DIAGNOSTIC] = NewSCSIDeviceOperation(SPCSendDiagnostics, nil, 0)
|
||||
sbc.SCSIDeviceOps[api.MODE_SENSE] = NewSCSIDeviceOperation(SBCModeSense, nil, PR_WE_FA|PR_EA_FA|PR_EA_FN|PR_WE_FN)
|
||||
sbc.SCSIDeviceOps[api.START_STOP] = NewSCSIDeviceOperation(SPCStartStop, nil, PR_SPECIAL)
|
||||
sbc.SCSIDeviceOps[api.SEND_DIAGNOSTIC] = NewSCSIDeviceOperation(SPCSendDiagnostics, nil, 0)
|
||||
|
||||
sbc.SCSIDeviceOps[ALLOW_MEDIUM_REMOVAL] = NewSCSIDeviceOperation(SPCPreventAllowMediaRemoval, nil, 0)
|
||||
sbc.SCSIDeviceOps[READ_CAPACITY] = NewSCSIDeviceOperation(SBCReadCapacity, nil, 0)
|
||||
sbc.SCSIDeviceOps[READ_10] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN)
|
||||
sbc.SCSIDeviceOps[WRITE_10] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_WE_FA|PR_EA_FA|PR_EA_FN|PR_WE_FN)
|
||||
sbc.SCSIDeviceOps[WRITE_VERIFY] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN)
|
||||
sbc.SCSIDeviceOps[VERIFY_10] = NewSCSIDeviceOperation(SBCVerify, nil, PR_EA_FA|PR_EA_FN)
|
||||
sbc.SCSIDeviceOps[api.ALLOW_MEDIUM_REMOVAL] = NewSCSIDeviceOperation(SPCPreventAllowMediaRemoval, nil, 0)
|
||||
sbc.SCSIDeviceOps[api.READ_CAPACITY] = NewSCSIDeviceOperation(SBCReadCapacity, nil, 0)
|
||||
sbc.SCSIDeviceOps[api.READ_10] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN)
|
||||
sbc.SCSIDeviceOps[api.WRITE_10] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_WE_FA|PR_EA_FA|PR_EA_FN|PR_WE_FN)
|
||||
sbc.SCSIDeviceOps[api.WRITE_VERIFY] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN)
|
||||
sbc.SCSIDeviceOps[api.VERIFY_10] = NewSCSIDeviceOperation(SBCVerify, nil, PR_EA_FA|PR_EA_FN)
|
||||
|
||||
sbc.SCSIDeviceOps[PRE_FETCH_10] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN)
|
||||
sbc.SCSIDeviceOps[SYNCHRONIZE_CACHE] = NewSCSIDeviceOperation(SBCSyncCache, nil, PR_WE_FA|PR_EA_FA|PR_WE_FN|PR_EA_FN)
|
||||
sbc.SCSIDeviceOps[api.PRE_FETCH_10] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN)
|
||||
sbc.SCSIDeviceOps[api.SYNCHRONIZE_CACHE] = NewSCSIDeviceOperation(SBCSyncCache, nil, PR_WE_FA|PR_EA_FA|PR_WE_FN|PR_EA_FN)
|
||||
|
||||
sbc.SCSIDeviceOps[WRITE_SAME] = NewSCSIDeviceOperation(SBCReadWrite, nil, 0)
|
||||
sbc.SCSIDeviceOps[UNMAP] = NewSCSIDeviceOperation(SBCUnmap, nil, 0)
|
||||
sbc.SCSIDeviceOps[api.WRITE_SAME] = NewSCSIDeviceOperation(SBCReadWrite, nil, 0)
|
||||
sbc.SCSIDeviceOps[api.UNMAP] = NewSCSIDeviceOperation(SBCUnmap, nil, 0)
|
||||
|
||||
sbc.SCSIDeviceOps[MODE_SELECT_10] = NewSCSIDeviceOperation(SBCModeSelect, nil, PR_WE_FA|PR_EA_FA|PR_EA_FN|PR_WE_FN)
|
||||
sbc.SCSIDeviceOps[MODE_SENSE_10] = NewSCSIDeviceOperation(SBCModeSense, nil, PR_WE_FA|PR_WE_FN|PR_EA_FA|PR_EA_FN)
|
||||
sbc.SCSIDeviceOps[PERSISTENT_RESERVE_IN] = NewSCSIDeviceOperation(SPCServiceAction, nil, 0)
|
||||
sbc.SCSIDeviceOps[PERSISTENT_RESERVE_OUT] = NewSCSIDeviceOperation(SPCServiceAction, nil, 0)
|
||||
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(SPCServiceAction, nil, 0)
|
||||
sbc.SCSIDeviceOps[api.PERSISTENT_RESERVE_OUT] = NewSCSIDeviceOperation(SPCServiceAction, nil, 0)
|
||||
|
||||
sbc.SCSIDeviceOps[READ_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN)
|
||||
sbc.SCSIDeviceOps[WRITE_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN|PR_WE_FA|PR_WE_FN)
|
||||
sbc.SCSIDeviceOps[ORWRITE_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN)
|
||||
sbc.SCSIDeviceOps[WRITE_VERIFY_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN)
|
||||
sbc.SCSIDeviceOps[VERIFY_16] = NewSCSIDeviceOperation(SBCVerify, 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.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.VERIFY_16] = NewSCSIDeviceOperation(SBCVerify, nil, PR_EA_FA|PR_EA_FN)
|
||||
|
||||
sbc.SCSIDeviceOps[PRE_FETCH_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN)
|
||||
sbc.SCSIDeviceOps[SYNCHRONIZE_CACHE_16] = NewSCSIDeviceOperation(SBCSyncCache, nil, PR_EA_FA|PR_EA_FN|PR_WE_FA|PR_WE_FN)
|
||||
sbc.SCSIDeviceOps[WRITE_SAME_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, 0)
|
||||
sbc.SCSIDeviceOps[SERVICE_ACTION_IN] = NewSCSIDeviceOperation(SPCServiceAction, nil, 0)
|
||||
sbc.SCSIDeviceOps[api.PRE_FETCH_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN)
|
||||
sbc.SCSIDeviceOps[api.SYNCHRONIZE_CACHE_16] = NewSCSIDeviceOperation(SBCSyncCache, nil, PR_EA_FA|PR_EA_FN|PR_WE_FA|PR_WE_FN)
|
||||
sbc.SCSIDeviceOps[api.WRITE_SAME_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, 0)
|
||||
sbc.SCSIDeviceOps[api.SERVICE_ACTION_IN] = NewSCSIDeviceOperation(SPCServiceAction, nil, 0)
|
||||
|
||||
sbc.SCSIDeviceOps[REPORT_LUNS] = NewSCSIDeviceOperation(SPCReportLuns, nil, 0)
|
||||
sbc.SCSIDeviceOps[EXCHANGE_MEDIUM] = NewSCSIDeviceOperation(SPCServiceAction, nil, 0)
|
||||
sbc.SCSIDeviceOps[READ_12] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN)
|
||||
sbc.SCSIDeviceOps[WRITE_12] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_WE_FA|PR_EA_FA|PR_WE_FA|PR_WE_FN)
|
||||
sbc.SCSIDeviceOps[WRITE_VERIFY_12] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN)
|
||||
sbc.SCSIDeviceOps[VERIFY_12] = NewSCSIDeviceOperation(SBCVerify, nil, PR_EA_FA|PR_EA_FN)
|
||||
sbc.SCSIDeviceOps[api.REPORT_LUNS] = NewSCSIDeviceOperation(SPCReportLuns, nil, 0)
|
||||
sbc.SCSIDeviceOps[api.EXCHANGE_MEDIUM] = NewSCSIDeviceOperation(SPCServiceAction, 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)
|
||||
sbc.SCSIDeviceOps[api.VERIFY_12] = NewSCSIDeviceOperation(SBCVerify, nil, PR_EA_FA|PR_EA_FN)
|
||||
|
||||
return sbc
|
||||
}
|
||||
|
||||
func SBCModeSelect(host int, cmd *SCSICommand) SAMStat {
|
||||
return SAMStatGood
|
||||
func SBCModeSelect(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
return api.SAMStatGood
|
||||
}
|
||||
|
||||
func SBCModeSense(host int, cmd *SCSICommand) SAMStat {
|
||||
func SBCModeSense(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
// DPOFUA = 0x10
|
||||
var deviceSpecific uint8 = 0x10
|
||||
|
||||
@@ -129,7 +142,7 @@ func SBCModeSense(host int, cmd *SCSICommand) SAMStat {
|
||||
data.WriteByte(deviceSpecific)
|
||||
}
|
||||
|
||||
return SAMStatGood
|
||||
return api.SAMStatGood
|
||||
}
|
||||
|
||||
// The FORMAT UNIT command requests that the device server format the medium into application client
|
||||
@@ -137,14 +150,14 @@ func SBCModeSense(host int, cmd *SCSICommand) SAMStat {
|
||||
// in the last mode parameter block descriptor in a MODE SELECT command (see SPC-3). In addition,
|
||||
// the device server may certify the medium and create control structures for the management of the medium and defects.
|
||||
// The degree that the medium is altered by this command is vendor-specific.
|
||||
func SBCFormatUnit(host int, cmd *SCSICommand) SAMStat {
|
||||
func SBCFormatUnit(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
var (
|
||||
key = ILLEGAL_REQUEST
|
||||
asc = ASC_INVALID_FIELD_IN_CDB
|
||||
)
|
||||
|
||||
if err := deviceReserve(cmd); err != nil {
|
||||
return SAMStatReservationConflict
|
||||
return api.SAMStatReservationConflict
|
||||
}
|
||||
|
||||
if !cmd.Device.Attrs.Online {
|
||||
@@ -172,33 +185,33 @@ func SBCFormatUnit(host int, cmd *SCSICommand) SAMStat {
|
||||
goto sense
|
||||
}
|
||||
|
||||
return SAMStatGood
|
||||
return api.SAMStatGood
|
||||
sense:
|
||||
BuildSenseData(cmd, key, asc)
|
||||
return SAMStatCheckCondition
|
||||
return api.SAMStatCheckCondition
|
||||
}
|
||||
|
||||
func SBCUnmap(host int, cmd *SCSICommand) SAMStat {
|
||||
return SAMStatGood
|
||||
func SBCUnmap(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
return api.SAMStatGood
|
||||
}
|
||||
|
||||
func SBCReadWrite(host int, cmd *SCSICommand) SAMStat {
|
||||
return SAMStatGood
|
||||
func SBCReadWrite(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
return api.SAMStatGood
|
||||
}
|
||||
|
||||
func SBCReserve(host int, cmd *SCSICommand) SAMStat {
|
||||
func SBCReserve(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
if err := deviceReserve(cmd); err != nil {
|
||||
return SAMStatReservationConflict
|
||||
return api.SAMStatReservationConflict
|
||||
}
|
||||
return SAMStatGood
|
||||
return api.SAMStatGood
|
||||
}
|
||||
|
||||
func SBCRelease(host int, cmd *SCSICommand) SAMStat {
|
||||
func SBCRelease(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
if err := deviceRelease(cmd.Target.TID, cmd.CommandITNID, cmd.Device.Lun, false); err != nil {
|
||||
return SAMStatReservationConflict
|
||||
return api.SAMStatReservationConflict
|
||||
}
|
||||
|
||||
return SAMStatGood
|
||||
return api.SAMStatGood
|
||||
}
|
||||
|
||||
// The READ CAPACITY (10) command requests that the device server transfer 8 bytes of parameter data
|
||||
@@ -206,7 +219,7 @@ func SBCRelease(host int, cmd *SCSICommand) SAMStat {
|
||||
// This command may be processed as if it has a HEAD OF QUEUE task attribute. If the logical unit supports
|
||||
// protection information, the application client should use the READ CAPACITY (16) command instead of
|
||||
// the READ CAPACITY (10) command.
|
||||
func SBCReadCapacity(host int, cmd *SCSICommand) SAMStat {
|
||||
func SBCReadCapacity(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
var (
|
||||
scb = cmd.SCB.Bytes()
|
||||
key = ILLEGAL_REQUEST
|
||||
@@ -242,15 +255,15 @@ func SBCReadCapacity(host int, cmd *SCSICommand) SAMStat {
|
||||
binary.Write(data, binary.BigEndian, uint32(1<<bshift))
|
||||
overflow:
|
||||
cmd.InSDBBuffer.Resid = 8
|
||||
return SAMStatGood
|
||||
return api.SAMStatGood
|
||||
sense:
|
||||
cmd.InSDBBuffer.Resid = 0
|
||||
BuildSenseData(cmd, key, asc)
|
||||
return SAMStatCheckCondition
|
||||
return api.SAMStatCheckCondition
|
||||
}
|
||||
|
||||
// The VERIFY (10) command requests that the device server verify the specified logical block(s) on the medium.
|
||||
func SBCVerify(host int, cmd *SCSICommand) SAMStat {
|
||||
func SBCVerify(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
var (
|
||||
key = ILLEGAL_REQUEST
|
||||
asc = ASC_INVALID_FIELD_IN_CDB
|
||||
@@ -270,30 +283,30 @@ func SBCVerify(host int, cmd *SCSICommand) SAMStat {
|
||||
|
||||
if cmd.SCB.Bytes()[1]&0x02 == 0 {
|
||||
// no data compare with the media
|
||||
return SAMStatGood
|
||||
return api.SAMStatGood
|
||||
}
|
||||
// TODO
|
||||
sense:
|
||||
cmd.InSDBBuffer.Resid = 0
|
||||
BuildSenseData(cmd, key, asc)
|
||||
return SAMStatCheckCondition
|
||||
return api.SAMStatCheckCondition
|
||||
}
|
||||
|
||||
func SBCReadCapacity16(host int, cmd *SCSICommand) SAMStat {
|
||||
return SAMStatGood
|
||||
func SBCReadCapacity16(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
return api.SAMStatGood
|
||||
}
|
||||
|
||||
func SBCGetLbaStatus(host int, cmd *SCSICommand) SAMStat {
|
||||
return SAMStatGood
|
||||
func SBCGetLbaStatus(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
return api.SAMStatGood
|
||||
}
|
||||
|
||||
func SBCServiceAction(host int, cmd *SCSICommand) SAMStat {
|
||||
return SAMStatGood
|
||||
func SBCServiceAction(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
return api.SAMStatGood
|
||||
}
|
||||
|
||||
// The SYNCHRONIZE CACHE (10) command requests that the device server ensure that
|
||||
// the specified logical blocks have their most recent data values recorded in
|
||||
// non-volatile cache and/or on the medium, based on the SYNC_NV bit.
|
||||
func SBCSyncCache(host int, cmd *SCSICommand) SAMStat {
|
||||
return SAMStatGood
|
||||
func SBCSyncCache(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
return api.SAMStatGood
|
||||
}
|
||||
|
||||
@@ -16,70 +16,9 @@ limitations under the License.
|
||||
|
||||
package scsi
|
||||
|
||||
import "errors"
|
||||
import "github.com/gostor/gotgt/pkg/api"
|
||||
|
||||
var (
|
||||
DefaultBlockShift int = 9
|
||||
DefaultSenseBufferSize int = 252
|
||||
)
|
||||
|
||||
type SCSIDeviceType byte
|
||||
|
||||
var (
|
||||
SAM_STAT_GOOD byte = 0x00
|
||||
SAM_STAT_CHECK_CONDITION byte = 0x02
|
||||
SAM_STAT_CONDITION_MET byte = 0x04
|
||||
SAM_STAT_BUSY byte = 0x08
|
||||
SAM_STAT_INTERMEDIATE byte = 0x10
|
||||
SAM_STAT_INTERMEDIATE_CONDITION_MET byte = 0x14
|
||||
SAM_STAT_RESERVATION_CONFLICT byte = 0x18
|
||||
SAM_STAT_COMMAND_TERMINATED byte = 0x22
|
||||
SAM_STAT_TASK_SET_FULL byte = 0x28
|
||||
SAM_STAT_ACA_ACTIVE byte = 0x30
|
||||
SAM_STAT_TASK_ABORTED byte = 0x40
|
||||
)
|
||||
|
||||
type SAMStat struct {
|
||||
Stat byte
|
||||
Err error
|
||||
}
|
||||
|
||||
var (
|
||||
SAMStatGood = SAMStat{SAM_STAT_GOOD, nil}
|
||||
SAMStatCheckCondition = SAMStat{SAM_STAT_CHECK_CONDITION, errors.New("check condition")}
|
||||
SAMStatConditionMet = SAMStat{SAM_STAT_CONDITION_MET, errors.New("condition met")}
|
||||
SAMStatBusy = SAMStat{SAM_STAT_BUSY, errors.New("busy")}
|
||||
SAMStatIntermediate = SAMStat{SAM_STAT_INTERMEDIATE, errors.New("intermediate")}
|
||||
SAMStatIntermediateConditionMet = SAMStat{SAM_STAT_INTERMEDIATE_CONDITION_MET, errors.New("intermediate condition met")}
|
||||
SAMStatReservationConflict = SAMStat{SAM_STAT_RESERVATION_CONFLICT, errors.New("reservation conflict")}
|
||||
SAMStatCommandTerminated = SAMStat{SAM_STAT_COMMAND_TERMINATED, errors.New("command terminated")}
|
||||
SAMStatTaskSetFull = SAMStat{SAM_STAT_TASK_SET_FULL, errors.New("task set full")}
|
||||
SAMStatAcaActive = SAMStat{SAM_STAT_ACA_ACTIVE, errors.New("aca active")}
|
||||
SAMStatTaskAborted = SAMStat{SAM_STAT_TASK_ABORTED, errors.New("task aborted")}
|
||||
)
|
||||
|
||||
var (
|
||||
TYPE_DISK SCSIDeviceType = 0x00
|
||||
TYPE_TAPE SCSIDeviceType = 0x01
|
||||
TYPE_PRINTER SCSIDeviceType = 0x02
|
||||
TYPE_PROCESSOR SCSIDeviceType = 0x03
|
||||
TYPE_WORM SCSIDeviceType = 0x04
|
||||
TYPE_MMC SCSIDeviceType = 0x05
|
||||
TYPE_SCANNER SCSIDeviceType = 0x06
|
||||
TYPE_MOD SCSIDeviceType = 0x07
|
||||
|
||||
TYPE_MEDIUM_CHANGER SCSIDeviceType = 0x08
|
||||
TYPE_COMM SCSIDeviceType = 0x09
|
||||
TYPE_RAID SCSIDeviceType = 0x0c
|
||||
TYPE_ENCLOSURE SCSIDeviceType = 0x0d
|
||||
TYPE_RBC SCSIDeviceType = 0x0e
|
||||
TYPE_OSD SCSIDeviceType = 0x11
|
||||
TYPE_NO_LUN SCSIDeviceType = 0x7f
|
||||
|
||||
TYPE_PT SCSIDeviceType = 0xff
|
||||
)
|
||||
|
||||
type CommandFunc func(host int, cmd *SCSICommand) SAMStat
|
||||
type CommandFunc func(host int, cmd *api.SCSICommand) api.SAMStat
|
||||
|
||||
type SCSIServiceAction struct {
|
||||
ServiceAction uint32
|
||||
@@ -93,16 +32,16 @@ type SCSIDeviceOperation struct {
|
||||
}
|
||||
|
||||
type BaseSCSIDeviceProtocol struct {
|
||||
Type SCSIDeviceType
|
||||
Type api.SCSIDeviceType
|
||||
SCSIDeviceOps []SCSIDeviceOperation
|
||||
}
|
||||
|
||||
type SCSIDeviceProtocol interface {
|
||||
InitLu(lu *SCSILu) error
|
||||
ExitLu(lu *SCSILu) error
|
||||
ConfigLu(lu *SCSILu) error
|
||||
OnlineLu(lu *SCSILu) error
|
||||
OfflineLu(lu *SCSILu) error
|
||||
InitLu(lu *api.SCSILu) error
|
||||
ExitLu(lu *api.SCSILu) error
|
||||
ConfigLu(lu *api.SCSILu) error
|
||||
OnlineLu(lu *api.SCSILu) error
|
||||
OfflineLu(lu *api.SCSILu) error
|
||||
}
|
||||
|
||||
func NewSCSIDeviceOperation(fn CommandFunc, sa *SCSIServiceAction, pr uint8) SCSIDeviceOperation {
|
||||
@@ -113,7 +52,7 @@ func NewSCSIDeviceOperation(fn CommandFunc, sa *SCSIServiceAction, pr uint8) SCS
|
||||
}
|
||||
}
|
||||
|
||||
func BuildSenseData(cmd *SCSICommand, key byte, asc SCSISubError) {
|
||||
func BuildSenseData(cmd *api.SCSICommand, key byte, asc SCSISubError) {
|
||||
senseBuffer := cmd.SenseBuffer
|
||||
if cmd.Device.Attrs.SenseFormat {
|
||||
// descriptor format
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"github.com/gostor/gotgt/pkg/api"
|
||||
"github.com/gostor/gotgt/pkg/util"
|
||||
)
|
||||
|
||||
@@ -108,16 +109,16 @@ const (
|
||||
DESG_SCSI
|
||||
)
|
||||
|
||||
func SPCIllegalOp(host int, cmd *SCSICommand) SAMStat {
|
||||
return SAMStatGood
|
||||
func SPCIllegalOp(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
return api.SAMStatGood
|
||||
}
|
||||
|
||||
func SPCLuOffline(lu *SCSILu) error {
|
||||
func SPCLuOffline(lu *api.SCSILu) error {
|
||||
lu.Attrs.Online = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func SPCLuOnline(lu *SCSILu) error {
|
||||
func SPCLuOnline(lu *api.SCSILu) error {
|
||||
if luPreventRemoval(lu) {
|
||||
return fmt.Errorf("lu(%s) prevent removal", lu.Lun)
|
||||
}
|
||||
@@ -126,11 +127,11 @@ func SPCLuOnline(lu *SCSILu) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func SPCInquiry(host int, cmd *SCSICommand) SAMStat {
|
||||
return SAMStatGood
|
||||
func SPCInquiry(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
return api.SAMStatGood
|
||||
}
|
||||
|
||||
func SPCReportLuns(host int, cmd *SCSICommand) SAMStat {
|
||||
func SPCReportLuns(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
var (
|
||||
remainLength uint32
|
||||
actualLength uint32 = 8
|
||||
@@ -171,26 +172,26 @@ func SPCReportLuns(host int, cmd *SCSICommand) SAMStat {
|
||||
remainLength -= 8
|
||||
}
|
||||
}
|
||||
return SAMStatGood
|
||||
return api.SAMStatGood
|
||||
sense:
|
||||
cmd.InSDBBuffer.Resid = 0
|
||||
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
|
||||
return SAMStatCheckCondition
|
||||
return api.SAMStatCheckCondition
|
||||
}
|
||||
|
||||
func SPCStartStop(host int, cmd *SCSICommand) SAMStat {
|
||||
func SPCStartStop(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
var (
|
||||
pwrcnd, loej, start byte
|
||||
)
|
||||
if err := deviceReserve(cmd); err != nil {
|
||||
return SAMStatReservationConflict
|
||||
return api.SAMStatReservationConflict
|
||||
}
|
||||
|
||||
cmd.InSDBBuffer.Resid = 0
|
||||
scb := cmd.SCB.Bytes()
|
||||
pwrcnd = scb[4] & 0xf0
|
||||
if pwrcnd != 0 {
|
||||
return SAMStatGood
|
||||
return api.SAMStatGood
|
||||
}
|
||||
|
||||
loej = scb[4] & 0x02
|
||||
@@ -205,7 +206,7 @@ func SPCStartStop(host int, cmd *SCSICommand) SAMStat {
|
||||
// !online == media is not present
|
||||
BuildSenseData(cmd, NOT_READY, ASC_MEDIUM_REMOVAL_PREVENTED)
|
||||
}
|
||||
return SAMStatCheckCondition
|
||||
return api.SAMStatCheckCondition
|
||||
}
|
||||
SPCLuOffline(cmd.Device)
|
||||
}
|
||||
@@ -213,15 +214,15 @@ func SPCStartStop(host int, cmd *SCSICommand) SAMStat {
|
||||
SPCLuOnline(cmd.Device)
|
||||
}
|
||||
|
||||
return SAMStatGood
|
||||
return api.SAMStatGood
|
||||
}
|
||||
|
||||
func SPCTestUnit(host int, cmd *SCSICommand) SAMStat {
|
||||
func SPCTestUnit(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
if err := deviceReserve(cmd); err != nil {
|
||||
return SAMStatReservationConflict
|
||||
return api.SAMStatReservationConflict
|
||||
}
|
||||
if cmd.Device.Attrs.Online {
|
||||
return SAMStatGood
|
||||
return api.SAMStatGood
|
||||
}
|
||||
if cmd.Device.Attrs.Removable {
|
||||
BuildSenseData(cmd, NOT_READY, ASC_MEDIUM_NOT_PRESENT)
|
||||
@@ -229,46 +230,46 @@ func SPCTestUnit(host int, cmd *SCSICommand) SAMStat {
|
||||
BuildSenseData(cmd, NOT_READY, ASC_BECOMING_READY)
|
||||
}
|
||||
|
||||
return SAMStatCheckCondition
|
||||
return api.SAMStatCheckCondition
|
||||
}
|
||||
|
||||
func SPCPreventAllowMediaRemoval(host int, cmd *SCSICommand) SAMStat {
|
||||
func SPCPreventAllowMediaRemoval(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
if err := deviceReserve(cmd); err != nil {
|
||||
return SAMStatReservationConflict
|
||||
return api.SAMStatReservationConflict
|
||||
}
|
||||
// PREVENT_MASK = 0x03
|
||||
cmd.ITNexusLuInfo.Prevent = int(cmd.SCB.Bytes()[4] & 0x03)
|
||||
return SAMStatGood
|
||||
return api.SAMStatGood
|
||||
}
|
||||
|
||||
// SPCModeSense Implement SCSI op MODE SENSE(6) and MODE SENSE(10)
|
||||
// Reference : SPC4r11
|
||||
// 6.11 - MODE SENSE(6)
|
||||
// 6.12 - MODE SENSE(10)
|
||||
func SPCModeSense(host int, cmd *SCSICommand) SAMStat {
|
||||
return SAMStatGood
|
||||
func SPCModeSense(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
return api.SAMStatGood
|
||||
}
|
||||
|
||||
func SPCSendDiagnostics(host int, cmd *SCSICommand) SAMStat {
|
||||
func SPCSendDiagnostics(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
// we only support SELF-TEST==1
|
||||
if cmd.SCB.Bytes()[1]&0x04 == 0 {
|
||||
goto sense
|
||||
}
|
||||
|
||||
return SAMStatGood
|
||||
return api.SAMStatGood
|
||||
sense:
|
||||
cmd.InSDBBuffer.Resid = 0
|
||||
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
|
||||
return SAMStatCheckCondition
|
||||
return api.SAMStatCheckCondition
|
||||
}
|
||||
|
||||
// This is useful for the various commands using the SERVICE ACTION format.
|
||||
func SPCServiceAction(host int, cmd *SCSICommand) SAMStat {
|
||||
func SPCServiceAction(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
// TODO
|
||||
return SAMStatGood
|
||||
return api.SAMStatGood
|
||||
}
|
||||
|
||||
func SPCPRReadKeys(host int, cmd *SCSICommand) SAMStat {
|
||||
func SPCPRReadKeys(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
allocationLength := util.GetUnalignedUint32(cmd.SCB.Bytes()[7:9])
|
||||
if allocationLength < 8 {
|
||||
goto sense
|
||||
@@ -280,14 +281,14 @@ func SPCPRReadKeys(host int, cmd *SCSICommand) SAMStat {
|
||||
sense:
|
||||
cmd.InSDBBuffer.Resid = 0
|
||||
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
|
||||
return SAMStatCheckCondition
|
||||
return api.SAMStatCheckCondition
|
||||
}
|
||||
|
||||
func SPCPRReadReservation(host int, cmd *SCSICommand) SAMStat {
|
||||
return SAMStatGood
|
||||
func SPCPRReadReservation(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
return api.SAMStatGood
|
||||
}
|
||||
|
||||
func SPCPRReportCapabilities(host int, cmd *SCSICommand) SAMStat {
|
||||
func SPCPRReportCapabilities(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
var (
|
||||
buf []byte = make([]byte, 8)
|
||||
availLength uint32 = 8
|
||||
@@ -324,38 +325,38 @@ func SPCPRReportCapabilities(host int, cmd *SCSICommand) SAMStat {
|
||||
actualLength = availLength
|
||||
}
|
||||
cmd.InSDBBuffer.Resid = int32(actualLength)
|
||||
return SAMStatGood
|
||||
return api.SAMStatGood
|
||||
sense:
|
||||
cmd.InSDBBuffer.Resid = 0
|
||||
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
|
||||
return SAMStatCheckCondition
|
||||
return api.SAMStatCheckCondition
|
||||
}
|
||||
|
||||
func SPCPRRegister(host int, cmd *SCSICommand) SAMStat {
|
||||
return SAMStatGood
|
||||
func SPCPRRegister(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
return api.SAMStatGood
|
||||
}
|
||||
|
||||
func SPCPRReserve(host int, cmd *SCSICommand) SAMStat {
|
||||
return SAMStatGood
|
||||
func SPCPRReserve(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
return api.SAMStatGood
|
||||
}
|
||||
|
||||
func SPCPRRelease(host int, cmd *SCSICommand) SAMStat {
|
||||
return SAMStatGood
|
||||
func SPCPRRelease(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
return api.SAMStatGood
|
||||
}
|
||||
|
||||
func SPCPRClear(host int, cmd *SCSICommand) SAMStat {
|
||||
return SAMStatGood
|
||||
func SPCPRClear(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
return api.SAMStatGood
|
||||
}
|
||||
|
||||
func SPCPRPreempt(host int, cmd *SCSICommand) SAMStat {
|
||||
return SAMStatGood
|
||||
func SPCPRPreempt(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
return api.SAMStatGood
|
||||
}
|
||||
|
||||
func SPCPRRegisterAndMove(host int, cmd *SCSICommand) SAMStat {
|
||||
return SAMStatGood
|
||||
func SPCPRRegisterAndMove(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
return api.SAMStatGood
|
||||
}
|
||||
|
||||
func SPCRequestSense(host int, cmd *SCSICommand) SAMStat {
|
||||
func SPCRequestSense(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
var (
|
||||
allocationLength uint32
|
||||
actualLength uint32
|
||||
@@ -378,5 +379,5 @@ func SPCRequestSense(host int, cmd *SCSICommand) SAMStat {
|
||||
cmd.SenseBuffer = &bytes.Buffer{}
|
||||
cmd.SenseLength = 0
|
||||
|
||||
return SAMStatGood
|
||||
return api.SAMStatGood
|
||||
}
|
||||
|
||||
@@ -20,50 +20,24 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/gostor/gotgt/pkg/api"
|
||||
"github.com/gostor/gotgt/pkg/port"
|
||||
)
|
||||
|
||||
type SCSITargetState int
|
||||
func NewTarget(tid int, driverName, name string) (*api.SCSITarget, error) {
|
||||
// verify the target ID
|
||||
|
||||
var (
|
||||
TargetOnline SCSITargetState = 1
|
||||
TargetReady SCSITargetState = 2
|
||||
)
|
||||
// verify the target's Name
|
||||
|
||||
const (
|
||||
PR_SPECIAL = (1 << 5)
|
||||
PR_WE_FA = (1 << 4)
|
||||
PR_EA_FA = (1 << 3)
|
||||
PR_RR_FR = (1 << 2)
|
||||
PR_WE_FN = (1 << 1)
|
||||
PR_EA_FN = (1 << 0)
|
||||
)
|
||||
|
||||
type ITNexus struct {
|
||||
ID uint64
|
||||
Ctime uint64
|
||||
Commands []SCSICommand
|
||||
Target *SCSITarget
|
||||
Host int
|
||||
Info string
|
||||
// verify the low level driver
|
||||
var target = &api.SCSITarget{Name: name, TID: tid}
|
||||
var tgt = port.NewTargetDriver(driverName, target)
|
||||
target.SCSITargetDriver = tgt
|
||||
return target, nil
|
||||
}
|
||||
|
||||
type ITNexusLuInfo struct {
|
||||
Lu *SCSILu
|
||||
ID uint64
|
||||
Prevent int
|
||||
}
|
||||
|
||||
type SCSITarget struct {
|
||||
Name string
|
||||
TID int
|
||||
LID int
|
||||
State SCSITargetState
|
||||
Devices []SCSILu
|
||||
ITNexus []ITNexus
|
||||
}
|
||||
|
||||
func deviceReserve(cmd *SCSICommand) error {
|
||||
var lu *SCSILu
|
||||
func deviceReserve(cmd *api.SCSICommand) error {
|
||||
var lu *api.SCSILu
|
||||
for _, dev := range cmd.Target.Devices {
|
||||
if dev.Lun == cmd.Device.Lun {
|
||||
lu = &dev
|
||||
|
||||
Reference in New Issue
Block a user