run the basic process with iscsi driver

This commit is contained in:
Lei Xue
2016-05-02 22:11:33 +08:00
parent d770eb33ac
commit c5d68b38b2
17 changed files with 948 additions and 633 deletions
+57 -1
View File
@@ -19,13 +19,69 @@ package main
import ( import (
"net" "net"
"os"
"reflect"
"github.com/golang/glog" "github.com/golang/glog"
"github.com/gostor/gotgt/pkg/api"
"github.com/gostor/gotgt/pkg/scsi"
) )
func main() { func main() {
_, err := net.Listen("tcp", ":3260") l, err := net.Listen("tcp", ":3260")
if err != nil { if err != nil {
glog.Error(err) 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
View 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
View 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 package iscsit
import ( import (
"bytes"
"fmt" "fmt"
"io"
"strings" "strings"
) )
@@ -70,15 +52,7 @@ var opCodeMap = map[OpCode]string{
OpReject: "Reject", OpReject: "Reject",
} }
func (c OpCode) String() string { type ISCSICommand struct {
s := opCodeMap[c]
if s == "" {
s = fmt.Sprintf("Unknown Code: %x", int(c))
}
return s
}
type Message struct {
OpCode OpCode OpCode OpCode
RawHeader []byte RawHeader []byte
DataLen int DataLen int
@@ -109,8 +83,8 @@ type Message struct {
// SCSI commands // SCSI commands
ExpectedDataLen uint32 ExpectedDataLen uint32
CDB []byte CDB []byte
Status Status Status byte
SCSIResponse Response SCSIResponse byte
// Data-In // Data-In
HasStatus bool HasStatus bool
@@ -118,23 +92,23 @@ type Message struct {
BufferOffset uint32 BufferOffset uint32
} }
func (m *Message) Bytes() []byte { func (cmd *ISCSICommand) Bytes() []byte {
switch m.OpCode { switch cmd.OpCode {
case OpLoginResp: case OpLoginResp:
return m.loginRespBytes() return cmd.loginRespBytes()
case OpLogoutResp: case OpLogoutResp:
return m.logoutRespBytes() return cmd.logoutRespBytes()
case OpSCSIResp: case OpSCSIResp:
return m.scsiCmdRespBytes() return cmd.scsiCmdRespBytes()
case OpSCSIIn: case OpSCSIIn:
return m.dataInBytes() return cmd.dataInBytes()
} }
return nil return nil
} }
func (m *Message) String() string { func (m *ISCSICommand) String() string {
var s []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("Final = %v", m.Final))
s = append(s, fmt.Sprintf("Immediate = %v", m.Immediate)) s = append(s, fmt.Sprintf("Immediate = %v", m.Immediate))
s = append(s, fmt.Sprintf("Data Segment Length = %d", m.DataLen)) 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") 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 // parseUint parses the given slice as a network-byte-ordered integer. If
// there are more than 8 bytes in data, it overflows. // there are more than 8 bytes in data, it overflows.
func ParseUint(data []byte) uint64 { func ParseUint(data []byte) uint64 {
@@ -220,13 +163,12 @@ func MarshalUint64(i uint64) []byte {
} }
return data return data
} }
func parseHeader(data []byte) (*ISCSICommand, error) {
func parseHeader(data []byte) (*Message, error) {
if len(data) != 48 { if len(data) != 48 {
return nil, fmt.Errorf("garbled header") return nil, fmt.Errorf("garbled header")
} }
// TODO: sync.Pool // TODO: sync.Pool
m := &Message{} m := &ISCSICommand{}
m.Immediate = 0x40&data[0] == 0x40 m.Immediate = 0x40&data[0] == 0x40
m.OpCode = OpCode(data[0] & 0x3f) m.OpCode = OpCode(data[0] & 0x3f)
m.Final = 0x80&data[1] == 0x80 m.Final = 0x80&data[1] == 0x80
@@ -274,3 +216,197 @@ func parseHeader(data []byte) (*Message, error) {
} }
return m, nil 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()
}
+106 -12
View File
@@ -17,6 +17,11 @@ limitations under the License.
// iSCSI Target Driver // iSCSI Target Driver
package iscsit package iscsit
import (
"github.com/gostor/gotgt/pkg/api"
"github.com/gostor/gotgt/pkg/util"
)
type ISCSIDiscoveryMethod string type ISCSIDiscoveryMethod string
var ( var (
@@ -33,9 +38,11 @@ type ISCSIRedirectInfo struct {
} }
type ISCSITarget struct { type ISCSITarget struct {
*api.SCSITarget
api.SCSITargetDriverCommon
Sessions []*ISCSISession Sessions []*ISCSISession
SessionParam []ISCSISessionParam SessionParam []ISCSISessionParam
TID int
Alias string Alias string
MaxSessions int MaxSessions int
RedirectInfo ISCSIRedirectInfo RedirectInfo ISCSIRedirectInfo
@@ -44,41 +51,128 @@ type ISCSITarget struct {
NopCount int NopCount int
} }
type ISCSITargetDriver struct { func NewISCSITarget(target *api.SCSITarget) *ISCSITarget {
SCSITargetDriver return &ISCSITarget{
SCSITarget: target,
}
} }
func (tgt *ISCSITargetDriver) Init() error { func (tgt *ISCSITarget) Init() error {
return nil return nil
} }
func (tgt *ISCSITargetDriver) Exit() error { func (tgt *ISCSITarget) Exit() error {
return nil return nil
} }
func (tgt *ISCSITargetDriver) CreateTarget(target *SCSITarget) error { func (tgt *ISCSITarget) CreateTarget(target *api.SCSITarget) error {
return nil return nil
} }
func (tgt *ISCSITargetDriver) DestroyTarget(target *SCSITarget) error { func (tgt *ISCSITarget) DestroyTarget(target *api.SCSITarget) error {
return nil return nil
} }
func (tgt *ISCSITargetDriver) CreatePortal(name string) error { func (tgt *ISCSITarget) CreatePortal(name string) error {
return nil return nil
} }
func (tgt *ISCSITargetDriver) DestroyPortal(name string) error { func (tgt *ISCSITarget) DestroyPortal(name string) error {
return nil return nil
} }
func (tgt *ISCSITargetDriver) CreateLu(lu *SCSILu) error { func (tgt *ISCSITarget) CreateLu(lu *api.SCSILu) error {
return nil return nil
} }
func (tgt *ISCSITargetDriver) GetLun(lun uint8) (uint64, error) { func (tgt *ISCSITarget) GetLu(lun uint8) (uint64, error) {
return 0, nil 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 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 -17
View File
@@ -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 package iscsit
import "bytes" import "bytes"
func (m *Message) loginRespBytes() []byte { func (m *ISCSICommand) loginRespBytes() []byte {
// rfc7143 11.13 // rfc7143 11.13
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
// byte 0 // byte 0
+1 -17
View File
@@ -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 package iscsit
import "bytes" import "bytes"
func (m *Message) logoutRespBytes() []byte { func (m *ISCSICommand) logoutRespBytes() []byte {
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
buf.WriteByte(byte(OpLogoutResp)) buf.WriteByte(byte(OpLogoutResp))
buf.WriteByte(0x80) buf.WriteByte(0x80)
+4 -1
View File
@@ -42,6 +42,9 @@ type ISCSISession struct {
Rdma int Rdma int
} }
type ISCSIHeader struct {
}
type ISCSIPdu struct { type ISCSIPdu struct {
Bhs ISCSIHeader Bhs ISCSIHeader
AhsSize uint AhsSize uint
@@ -78,7 +81,7 @@ func NewISCSISession() (*ISCSISession, error) {
tsih += uint16(b[0]) << 8 tsih += uint16(b[0]) << 8
tsih += uint16(b[1]) tsih += uint16(b[1])
return &Session{ return &ISCSISession{
Tsih: tsih, Tsih: tsih,
}, nil }, nil
} }
+15 -11
View File
@@ -16,7 +16,11 @@ limitations under the License.
package scsi package scsi
import "fmt" import (
"fmt"
"github.com/gostor/gotgt/pkg/api"
)
type BaseBackingStore struct { type BaseBackingStore struct {
Name string Name string
@@ -25,11 +29,11 @@ type BaseBackingStore struct {
} }
type BackingStore interface { type BackingStore interface {
Open(dev *SCSILu, path string, fd *int, size *uint64) error Open(dev *api.SCSILu, path string, fd *int, size *uint64) error
Close(dev *SCSILu) error Close(dev *api.SCSILu) error
Init(dev *SCSILu, Opts string) error Init(dev *api.SCSILu, Opts string) error
Exit(dev *SCSILu) error Exit(dev *api.SCSILu) error
CommandSubmit(cmd *SCSICommand) error CommandSubmit(cmd *api.SCSICommand) error
} }
type BackingStoreFunc func() (BackingStore, error) type BackingStoreFunc func() (BackingStore, error)
@@ -55,22 +59,22 @@ type fakeBackingStore struct {
BaseBackingStore 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 return nil
} }
func (fake *fakeBackingStore) Close(dev *SCSILu) error { func (fake *fakeBackingStore) Close(dev *api.SCSILu) error {
return nil return nil
} }
func (fake *fakeBackingStore) Init(dev *SCSILu, Opts string) error { func (fake *fakeBackingStore) Init(dev *api.SCSILu, Opts string) error {
return nil return nil
} }
func (fake *fakeBackingStore) Exit(dev *SCSILu) error { func (fake *fakeBackingStore) Exit(dev *api.SCSILu) error {
return nil return nil
} }
func (fake *fakeBackingStore) CommandSubmit(cmd *SCSICommand) error { func (fake *fakeBackingStore) CommandSubmit(cmd *api.SCSICommand) error {
return nil return nil
} }
+7 -1
View File
@@ -16,7 +16,11 @@ limitations under the License.
package backingstore package backingstore
import "github.com/gostor/gotgt/pkg/scsi" import (
"github.com/gostor/gotgt/pkg/scsi"
"github.com/golang/glog"
)
func init() { func init() {
scsi.RegisterBackingStore("null", new) 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 { 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 return nil
} }
@@ -51,5 +56,6 @@ func (bs *NullBackingStore) Exit(dev *SCSILu) error {
} }
func (bs *NullBackingStore) CommandSubmit(cmd *SCSICommand) error { func (bs *NullBackingStore) CommandSubmit(cmd *SCSICommand) error {
cmd.Result = SAM_STAT_GOOD
return nil return nil
} }
-147
View File
@@ -16,113 +16,6 @@ limitations under the License.
package scsi 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 SCSIPRServiceAction byte
type SCSIPRType byte type SCSIPRType byte
@@ -155,15 +48,6 @@ var (
PR_TYPE_EXCLUSIVE_ACCESS_ALLREG SCSIPRType = 0x08 PR_TYPE_EXCLUSIVE_ACCESS_ALLREG SCSIPRType = 0x08
) )
type SCSIDataDirection int
const (
SCSIDataNone = iota
SCSIDataWrite
SCSIDataRead
SCSIDataBidirection
)
const ( const (
CBD_GROUPID_0 = iota CBD_GROUPID_0 = iota
CBD_GROUPID_1 CBD_GROUPID_1
@@ -186,37 +70,6 @@ const (
CDB_GROUP7 = 0 /* vendor specific */ 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 { func SCSICDBGroupID(opcode byte) byte {
return ((opcode >> 5) & 0x7) return ((opcode >> 5) & 0x7)
} }
-73
View File
@@ -16,76 +16,3 @@ limitations under the License.
// Target Driver Interface // Target Driver Interface
package scsi 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
}
+8 -44
View File
@@ -16,58 +16,22 @@ limitations under the License.
package scsi package scsi
type SCSILuPhyAttribute struct { import "github.com/gostor/gotgt/pkg/api"
SCSIID string
SCSISN string type SCSILuOps struct {
NumID uint64 *api.SCSILu
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
}
type SCSILu struct {
FD int
Address uint64
Size uint64
Lun uint64
Path string
BsoFlags int
BlockShift uint
ReserveID uint64
DeviceProtocol SCSIDeviceProtocol DeviceProtocol SCSIDeviceProtocol
Storage *BackingStore Storage *BackingStore
Target *SCSITarget Target *api.SCSITarget
Attrs SCSILuPhyAttribute Attrs api.SCSILuPhyAttribute
// function handler for command performing and finishing // function handler for command performing and finishing
PerformCommand CommandFunc PerformCommand CommandFunc
FinishCommand func(*SCSITarget, *SCSICommand) FinishCommand func(*api.SCSITarget, *api.SCSICommand)
} }
func luPreventRemoval(lu *SCSILu) bool { func luPreventRemoval(lu *api.SCSILu) bool {
// TODO // TODO
return false return false
} }
+93 -80
View File
@@ -17,96 +17,109 @@ limitations under the License.
// SCSI block command processing // SCSI block command processing
package scsi 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 { type SBCSCSIDeviceProtocol struct {
BaseSCSIDeviceProtocol BaseSCSIDeviceProtocol
} }
func (sbc *SBCSCSIDeviceProtocol) InitLu(lu *SCSILu) error { func (sbc *SBCSCSIDeviceProtocol) InitLu(lu *api.SCSILu) error {
return nil return nil
} }
func (sbc *SBCSCSIDeviceProtocol) ExitLu(lu *SCSILu) error { func (sbc *SBCSCSIDeviceProtocol) ExitLu(lu *api.SCSILu) error {
return nil return nil
} }
func (sbc *SBCSCSIDeviceProtocol) ConfigLu(lu *SCSILu) error { func (sbc *SBCSCSIDeviceProtocol) ConfigLu(lu *api.SCSILu) error {
return nil return nil
} }
func (sbc *SBCSCSIDeviceProtocol) OnlineLu(lu *SCSILu) error { func (sbc *SBCSCSIDeviceProtocol) OnlineLu(lu *api.SCSILu) error {
return nil return nil
} }
func (sbc *SBCSCSIDeviceProtocol) OfflineLu(lu *SCSILu) error { func (sbc *SBCSCSIDeviceProtocol) OfflineLu(lu *api.SCSILu) error {
return nil return nil
} }
func NewSBCDevice() SBCSCSIDeviceProtocol { func NewSBCDevice() SBCSCSIDeviceProtocol {
var sbc = SBCSCSIDeviceProtocol{ var sbc = SBCSCSIDeviceProtocol{
BaseSCSIDeviceProtocol{ BaseSCSIDeviceProtocol{
Type: TYPE_DISK, Type: api.TYPE_DISK,
SCSIDeviceOps: make([]SCSIDeviceOperation, 256), SCSIDeviceOps: make([]SCSIDeviceOperation, 256),
}, },
} }
for i := 0; i <= 256; i++ { for i := 0; i <= 256; i++ {
sbc.SCSIDeviceOps = append(sbc.SCSIDeviceOps, NewSCSIDeviceOperation(SPCIllegalOp, nil, 0)) sbc.SCSIDeviceOps = append(sbc.SCSIDeviceOps, NewSCSIDeviceOperation(SPCIllegalOp, nil, 0))
} }
sbc.SCSIDeviceOps[TEST_UNIT_READY] = NewSCSIDeviceOperation(SPCTestUnit, nil, 0) sbc.SCSIDeviceOps[api.TEST_UNIT_READY] = NewSCSIDeviceOperation(SPCTestUnit, nil, 0)
sbc.SCSIDeviceOps[REQUEST_SENSE] = NewSCSIDeviceOperation(SPCRequestSense, nil, 0) sbc.SCSIDeviceOps[api.REQUEST_SENSE] = NewSCSIDeviceOperation(SPCRequestSense, nil, 0)
sbc.SCSIDeviceOps[FORMAT_UNIT] = NewSCSIDeviceOperation(SBCFormatUnit, nil, 0) sbc.SCSIDeviceOps[api.FORMAT_UNIT] = NewSCSIDeviceOperation(SBCFormatUnit, nil, 0)
sbc.SCSIDeviceOps[READ_6] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN) sbc.SCSIDeviceOps[api.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[api.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[api.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[api.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[api.RESERVE] = NewSCSIDeviceOperation(SBCReserve, nil, 0)
sbc.SCSIDeviceOps[RELEASE] = NewSCSIDeviceOperation(SBCRelease, 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[api.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[api.START_STOP] = NewSCSIDeviceOperation(SPCStartStop, nil, PR_SPECIAL)
sbc.SCSIDeviceOps[SEND_DIAGNOSTIC] = NewSCSIDeviceOperation(SPCSendDiagnostics, nil, 0) sbc.SCSIDeviceOps[api.SEND_DIAGNOSTIC] = NewSCSIDeviceOperation(SPCSendDiagnostics, nil, 0)
sbc.SCSIDeviceOps[ALLOW_MEDIUM_REMOVAL] = NewSCSIDeviceOperation(SPCPreventAllowMediaRemoval, nil, 0) sbc.SCSIDeviceOps[api.ALLOW_MEDIUM_REMOVAL] = NewSCSIDeviceOperation(SPCPreventAllowMediaRemoval, nil, 0)
sbc.SCSIDeviceOps[READ_CAPACITY] = NewSCSIDeviceOperation(SBCReadCapacity, nil, 0) sbc.SCSIDeviceOps[api.READ_CAPACITY] = NewSCSIDeviceOperation(SBCReadCapacity, nil, 0)
sbc.SCSIDeviceOps[READ_10] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN) sbc.SCSIDeviceOps[api.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[api.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[api.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.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[api.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.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[api.WRITE_SAME] = NewSCSIDeviceOperation(SBCReadWrite, nil, 0)
sbc.SCSIDeviceOps[UNMAP] = NewSCSIDeviceOperation(SBCUnmap, 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[api.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[api.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[api.PERSISTENT_RESERVE_IN] = NewSCSIDeviceOperation(SPCServiceAction, nil, 0)
sbc.SCSIDeviceOps[PERSISTENT_RESERVE_OUT] = 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[api.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[api.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[api.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[api.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.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[api.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[api.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[api.WRITE_SAME_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, 0)
sbc.SCSIDeviceOps[SERVICE_ACTION_IN] = NewSCSIDeviceOperation(SPCServiceAction, nil, 0) sbc.SCSIDeviceOps[api.SERVICE_ACTION_IN] = NewSCSIDeviceOperation(SPCServiceAction, nil, 0)
sbc.SCSIDeviceOps[REPORT_LUNS] = NewSCSIDeviceOperation(SPCReportLuns, nil, 0) sbc.SCSIDeviceOps[api.REPORT_LUNS] = NewSCSIDeviceOperation(SPCReportLuns, nil, 0)
sbc.SCSIDeviceOps[EXCHANGE_MEDIUM] = NewSCSIDeviceOperation(SPCServiceAction, nil, 0) sbc.SCSIDeviceOps[api.EXCHANGE_MEDIUM] = NewSCSIDeviceOperation(SPCServiceAction, nil, 0)
sbc.SCSIDeviceOps[READ_12] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN) sbc.SCSIDeviceOps[api.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[api.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[api.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.VERIFY_12] = NewSCSIDeviceOperation(SBCVerify, nil, PR_EA_FA|PR_EA_FN)
return sbc return sbc
} }
func SBCModeSelect(host int, cmd *SCSICommand) SAMStat { func SBCModeSelect(host int, cmd *api.SCSICommand) api.SAMStat {
return SAMStatGood return api.SAMStatGood
} }
func SBCModeSense(host int, cmd *SCSICommand) SAMStat { func SBCModeSense(host int, cmd *api.SCSICommand) api.SAMStat {
// DPOFUA = 0x10 // DPOFUA = 0x10
var deviceSpecific uint8 = 0x10 var deviceSpecific uint8 = 0x10
@@ -129,7 +142,7 @@ func SBCModeSense(host int, cmd *SCSICommand) SAMStat {
data.WriteByte(deviceSpecific) data.WriteByte(deviceSpecific)
} }
return SAMStatGood return api.SAMStatGood
} }
// The FORMAT UNIT command requests that the device server format the medium into application client // 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, // 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 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. // 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 ( var (
key = ILLEGAL_REQUEST key = ILLEGAL_REQUEST
asc = ASC_INVALID_FIELD_IN_CDB asc = ASC_INVALID_FIELD_IN_CDB
) )
if err := deviceReserve(cmd); err != nil { if err := deviceReserve(cmd); err != nil {
return SAMStatReservationConflict return api.SAMStatReservationConflict
} }
if !cmd.Device.Attrs.Online { if !cmd.Device.Attrs.Online {
@@ -172,33 +185,33 @@ func SBCFormatUnit(host int, cmd *SCSICommand) SAMStat {
goto sense goto sense
} }
return SAMStatGood return api.SAMStatGood
sense: sense:
BuildSenseData(cmd, key, asc) BuildSenseData(cmd, key, asc)
return SAMStatCheckCondition return api.SAMStatCheckCondition
} }
func SBCUnmap(host int, cmd *SCSICommand) SAMStat { func SBCUnmap(host int, cmd *api.SCSICommand) api.SAMStat {
return SAMStatGood return api.SAMStatGood
} }
func SBCReadWrite(host int, cmd *SCSICommand) SAMStat { func SBCReadWrite(host int, cmd *api.SCSICommand) api.SAMStat {
return SAMStatGood 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 { 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 { 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 // 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 // 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 // protection information, the application client should use the READ CAPACITY (16) command instead of
// the READ CAPACITY (10) command. // the READ CAPACITY (10) command.
func SBCReadCapacity(host int, cmd *SCSICommand) SAMStat { func SBCReadCapacity(host int, cmd *api.SCSICommand) api.SAMStat {
var ( var (
scb = cmd.SCB.Bytes() scb = cmd.SCB.Bytes()
key = ILLEGAL_REQUEST key = ILLEGAL_REQUEST
@@ -242,15 +255,15 @@ func SBCReadCapacity(host int, cmd *SCSICommand) SAMStat {
binary.Write(data, binary.BigEndian, uint32(1<<bshift)) binary.Write(data, binary.BigEndian, uint32(1<<bshift))
overflow: overflow:
cmd.InSDBBuffer.Resid = 8 cmd.InSDBBuffer.Resid = 8
return SAMStatGood return api.SAMStatGood
sense: sense:
cmd.InSDBBuffer.Resid = 0 cmd.InSDBBuffer.Resid = 0
BuildSenseData(cmd, key, asc) 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. // 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 ( var (
key = ILLEGAL_REQUEST key = ILLEGAL_REQUEST
asc = ASC_INVALID_FIELD_IN_CDB asc = ASC_INVALID_FIELD_IN_CDB
@@ -270,30 +283,30 @@ func SBCVerify(host int, cmd *SCSICommand) SAMStat {
if cmd.SCB.Bytes()[1]&0x02 == 0 { if cmd.SCB.Bytes()[1]&0x02 == 0 {
// no data compare with the media // no data compare with the media
return SAMStatGood return api.SAMStatGood
} }
// TODO // TODO
sense: sense:
cmd.InSDBBuffer.Resid = 0 cmd.InSDBBuffer.Resid = 0
BuildSenseData(cmd, key, asc) BuildSenseData(cmd, key, asc)
return SAMStatCheckCondition return api.SAMStatCheckCondition
} }
func SBCReadCapacity16(host int, cmd *SCSICommand) SAMStat { func SBCReadCapacity16(host int, cmd *api.SCSICommand) api.SAMStat {
return SAMStatGood return api.SAMStatGood
} }
func SBCGetLbaStatus(host int, cmd *SCSICommand) SAMStat { func SBCGetLbaStatus(host int, cmd *api.SCSICommand) api.SAMStat {
return SAMStatGood return api.SAMStatGood
} }
func SBCServiceAction(host int, cmd *SCSICommand) SAMStat { func SBCServiceAction(host int, cmd *api.SCSICommand) api.SAMStat {
return SAMStatGood return api.SAMStatGood
} }
// The SYNCHRONIZE CACHE (10) command requests that the device server ensure that // The SYNCHRONIZE CACHE (10) command requests that the device server ensure that
// the specified logical blocks have their most recent data values recorded in // 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. // non-volatile cache and/or on the medium, based on the SYNC_NV bit.
func SBCSyncCache(host int, cmd *SCSICommand) SAMStat { func SBCSyncCache(host int, cmd *api.SCSICommand) api.SAMStat {
return SAMStatGood return api.SAMStatGood
} }
+9 -70
View File
@@ -16,70 +16,9 @@ limitations under the License.
package scsi package scsi
import "errors" import "github.com/gostor/gotgt/pkg/api"
var ( type CommandFunc func(host int, cmd *api.SCSICommand) api.SAMStat
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 SCSIServiceAction struct { type SCSIServiceAction struct {
ServiceAction uint32 ServiceAction uint32
@@ -93,16 +32,16 @@ type SCSIDeviceOperation struct {
} }
type BaseSCSIDeviceProtocol struct { type BaseSCSIDeviceProtocol struct {
Type SCSIDeviceType Type api.SCSIDeviceType
SCSIDeviceOps []SCSIDeviceOperation SCSIDeviceOps []SCSIDeviceOperation
} }
type SCSIDeviceProtocol interface { type SCSIDeviceProtocol interface {
InitLu(lu *SCSILu) error InitLu(lu *api.SCSILu) error
ExitLu(lu *SCSILu) error ExitLu(lu *api.SCSILu) error
ConfigLu(lu *SCSILu) error ConfigLu(lu *api.SCSILu) error
OnlineLu(lu *SCSILu) error OnlineLu(lu *api.SCSILu) error
OfflineLu(lu *SCSILu) error OfflineLu(lu *api.SCSILu) error
} }
func NewSCSIDeviceOperation(fn CommandFunc, sa *SCSIServiceAction, pr uint8) SCSIDeviceOperation { 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 senseBuffer := cmd.SenseBuffer
if cmd.Device.Attrs.SenseFormat { if cmd.Device.Attrs.SenseFormat {
// descriptor format // descriptor format
+50 -49
View File
@@ -22,6 +22,7 @@ import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"github.com/gostor/gotgt/pkg/api"
"github.com/gostor/gotgt/pkg/util" "github.com/gostor/gotgt/pkg/util"
) )
@@ -108,16 +109,16 @@ const (
DESG_SCSI DESG_SCSI
) )
func SPCIllegalOp(host int, cmd *SCSICommand) SAMStat { func SPCIllegalOp(host int, cmd *api.SCSICommand) api.SAMStat {
return SAMStatGood return api.SAMStatGood
} }
func SPCLuOffline(lu *SCSILu) error { func SPCLuOffline(lu *api.SCSILu) error {
lu.Attrs.Online = true lu.Attrs.Online = true
return nil return nil
} }
func SPCLuOnline(lu *SCSILu) error { func SPCLuOnline(lu *api.SCSILu) error {
if luPreventRemoval(lu) { if luPreventRemoval(lu) {
return fmt.Errorf("lu(%s) prevent removal", lu.Lun) return fmt.Errorf("lu(%s) prevent removal", lu.Lun)
} }
@@ -126,11 +127,11 @@ func SPCLuOnline(lu *SCSILu) error {
return nil return nil
} }
func SPCInquiry(host int, cmd *SCSICommand) SAMStat { func SPCInquiry(host int, cmd *api.SCSICommand) api.SAMStat {
return SAMStatGood return api.SAMStatGood
} }
func SPCReportLuns(host int, cmd *SCSICommand) SAMStat { func SPCReportLuns(host int, cmd *api.SCSICommand) api.SAMStat {
var ( var (
remainLength uint32 remainLength uint32
actualLength uint32 = 8 actualLength uint32 = 8
@@ -171,26 +172,26 @@ func SPCReportLuns(host int, cmd *SCSICommand) SAMStat {
remainLength -= 8 remainLength -= 8
} }
} }
return SAMStatGood return api.SAMStatGood
sense: sense:
cmd.InSDBBuffer.Resid = 0 cmd.InSDBBuffer.Resid = 0
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB) 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 ( var (
pwrcnd, loej, start byte pwrcnd, loej, start byte
) )
if err := deviceReserve(cmd); err != nil { if err := deviceReserve(cmd); err != nil {
return SAMStatReservationConflict return api.SAMStatReservationConflict
} }
cmd.InSDBBuffer.Resid = 0 cmd.InSDBBuffer.Resid = 0
scb := cmd.SCB.Bytes() scb := cmd.SCB.Bytes()
pwrcnd = scb[4] & 0xf0 pwrcnd = scb[4] & 0xf0
if pwrcnd != 0 { if pwrcnd != 0 {
return SAMStatGood return api.SAMStatGood
} }
loej = scb[4] & 0x02 loej = scb[4] & 0x02
@@ -205,7 +206,7 @@ func SPCStartStop(host int, cmd *SCSICommand) SAMStat {
// !online == media is not present // !online == media is not present
BuildSenseData(cmd, NOT_READY, ASC_MEDIUM_REMOVAL_PREVENTED) BuildSenseData(cmd, NOT_READY, ASC_MEDIUM_REMOVAL_PREVENTED)
} }
return SAMStatCheckCondition return api.SAMStatCheckCondition
} }
SPCLuOffline(cmd.Device) SPCLuOffline(cmd.Device)
} }
@@ -213,15 +214,15 @@ func SPCStartStop(host int, cmd *SCSICommand) SAMStat {
SPCLuOnline(cmd.Device) 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 { if err := deviceReserve(cmd); err != nil {
return SAMStatReservationConflict return api.SAMStatReservationConflict
} }
if cmd.Device.Attrs.Online { if cmd.Device.Attrs.Online {
return SAMStatGood return api.SAMStatGood
} }
if cmd.Device.Attrs.Removable { if cmd.Device.Attrs.Removable {
BuildSenseData(cmd, NOT_READY, ASC_MEDIUM_NOT_PRESENT) 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) 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 { if err := deviceReserve(cmd); err != nil {
return SAMStatReservationConflict return api.SAMStatReservationConflict
} }
// PREVENT_MASK = 0x03 // PREVENT_MASK = 0x03
cmd.ITNexusLuInfo.Prevent = int(cmd.SCB.Bytes()[4] & 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) // SPCModeSense Implement SCSI op MODE SENSE(6) and MODE SENSE(10)
// Reference : SPC4r11 // Reference : SPC4r11
// 6.11 - MODE SENSE(6) // 6.11 - MODE SENSE(6)
// 6.12 - MODE SENSE(10) // 6.12 - MODE SENSE(10)
func SPCModeSense(host int, cmd *SCSICommand) SAMStat { func SPCModeSense(host int, cmd *api.SCSICommand) api.SAMStat {
return SAMStatGood 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 // we only support SELF-TEST==1
if cmd.SCB.Bytes()[1]&0x04 == 0 { if cmd.SCB.Bytes()[1]&0x04 == 0 {
goto sense goto sense
} }
return SAMStatGood return api.SAMStatGood
sense: sense:
cmd.InSDBBuffer.Resid = 0 cmd.InSDBBuffer.Resid = 0
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB) 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. // 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 // 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]) allocationLength := util.GetUnalignedUint32(cmd.SCB.Bytes()[7:9])
if allocationLength < 8 { if allocationLength < 8 {
goto sense goto sense
@@ -280,14 +281,14 @@ func SPCPRReadKeys(host int, cmd *SCSICommand) SAMStat {
sense: sense:
cmd.InSDBBuffer.Resid = 0 cmd.InSDBBuffer.Resid = 0
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB) BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
return SAMStatCheckCondition return api.SAMStatCheckCondition
} }
func SPCPRReadReservation(host int, cmd *SCSICommand) SAMStat { func SPCPRReadReservation(host int, cmd *api.SCSICommand) api.SAMStat {
return SAMStatGood return api.SAMStatGood
} }
func SPCPRReportCapabilities(host int, cmd *SCSICommand) SAMStat { func SPCPRReportCapabilities(host int, cmd *api.SCSICommand) api.SAMStat {
var ( var (
buf []byte = make([]byte, 8) buf []byte = make([]byte, 8)
availLength uint32 = 8 availLength uint32 = 8
@@ -324,38 +325,38 @@ func SPCPRReportCapabilities(host int, cmd *SCSICommand) SAMStat {
actualLength = availLength actualLength = availLength
} }
cmd.InSDBBuffer.Resid = int32(actualLength) cmd.InSDBBuffer.Resid = int32(actualLength)
return SAMStatGood return api.SAMStatGood
sense: sense:
cmd.InSDBBuffer.Resid = 0 cmd.InSDBBuffer.Resid = 0
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB) BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
return SAMStatCheckCondition return api.SAMStatCheckCondition
} }
func SPCPRRegister(host int, cmd *SCSICommand) SAMStat { func SPCPRRegister(host int, cmd *api.SCSICommand) api.SAMStat {
return SAMStatGood return api.SAMStatGood
} }
func SPCPRReserve(host int, cmd *SCSICommand) SAMStat { func SPCPRReserve(host int, cmd *api.SCSICommand) api.SAMStat {
return SAMStatGood return api.SAMStatGood
} }
func SPCPRRelease(host int, cmd *SCSICommand) SAMStat { func SPCPRRelease(host int, cmd *api.SCSICommand) api.SAMStat {
return SAMStatGood return api.SAMStatGood
} }
func SPCPRClear(host int, cmd *SCSICommand) SAMStat { func SPCPRClear(host int, cmd *api.SCSICommand) api.SAMStat {
return SAMStatGood return api.SAMStatGood
} }
func SPCPRPreempt(host int, cmd *SCSICommand) SAMStat { func SPCPRPreempt(host int, cmd *api.SCSICommand) api.SAMStat {
return SAMStatGood return api.SAMStatGood
} }
func SPCPRRegisterAndMove(host int, cmd *SCSICommand) SAMStat { func SPCPRRegisterAndMove(host int, cmd *api.SCSICommand) api.SAMStat {
return SAMStatGood return api.SAMStatGood
} }
func SPCRequestSense(host int, cmd *SCSICommand) SAMStat { func SPCRequestSense(host int, cmd *api.SCSICommand) api.SAMStat {
var ( var (
allocationLength uint32 allocationLength uint32
actualLength uint32 actualLength uint32
@@ -378,5 +379,5 @@ func SPCRequestSense(host int, cmd *SCSICommand) SAMStat {
cmd.SenseBuffer = &bytes.Buffer{} cmd.SenseBuffer = &bytes.Buffer{}
cmd.SenseLength = 0 cmd.SenseLength = 0
return SAMStatGood return api.SAMStatGood
} }
+12 -38
View File
@@ -20,50 +20,24 @@ import (
"fmt" "fmt"
"github.com/golang/glog" "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 ( // verify the target's Name
TargetOnline SCSITargetState = 1
TargetReady SCSITargetState = 2
)
const ( // verify the low level driver
PR_SPECIAL = (1 << 5) var target = &api.SCSITarget{Name: name, TID: tid}
PR_WE_FA = (1 << 4) var tgt = port.NewTargetDriver(driverName, target)
PR_EA_FA = (1 << 3) target.SCSITargetDriver = tgt
PR_RR_FR = (1 << 2) return target, nil
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
} }
type ITNexusLuInfo struct { func deviceReserve(cmd *api.SCSICommand) error {
Lu *SCSILu var lu *api.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
for _, dev := range cmd.Target.Devices { for _, dev := range cmd.Target.Devices {
if dev.Lun == cmd.Device.Lun { if dev.Lun == cmd.Device.Lun {
lu = &dev lu = &dev