From c5d68b38b2e6990f7a264abb7e37003b9df8977c Mon Sep 17 00:00:00 2001 From: Lei Xue Date: Mon, 2 May 2016 22:11:33 +0800 Subject: [PATCH] run the basic process with iscsi driver --- citd.go | 58 ++++- pkg/api/types.go | 307 ++++++++++++++++++++++++++ pkg/port/interfaces.go | 70 ++++++ pkg/port/iscsit/{packet.go => cmd.go} | 280 +++++++++++++++++------ pkg/port/iscsit/iscsit.go | 118 +++++++++- pkg/port/iscsit/login.go | 18 +- pkg/port/iscsit/logout.go | 18 +- pkg/port/iscsit/session.go | 5 +- pkg/scsi/backingstore.go | 26 ++- pkg/scsi/backingstore/null.go | 8 +- pkg/scsi/cmd.go | 147 ------------ pkg/scsi/drivers.go | 73 ------ pkg/scsi/lun.go | 52 +---- pkg/scsi/sbc.go | 173 ++++++++------- pkg/scsi/scsi.go | 79 +------ pkg/scsi/spc.go | 99 +++++---- pkg/scsi/target.go | 50 +---- 17 files changed, 948 insertions(+), 633 deletions(-) create mode 100644 pkg/api/types.go create mode 100644 pkg/port/interfaces.go rename pkg/port/iscsit/{packet.go => cmd.go} (57%) diff --git a/citd.go b/citd.go index 5df3aef..ef2bfed 100644 --- a/citd.go +++ b/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) } } diff --git a/pkg/api/types.go b/pkg/api/types.go new file mode 100644 index 0000000..12430e2 --- /dev/null +++ b/pkg/api/types.go @@ -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 +} diff --git a/pkg/port/interfaces.go b/pkg/port/interfaces.go new file mode 100644 index 0000000..b2e6b94 --- /dev/null +++ b/pkg/port/interfaces.go @@ -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 +} diff --git a/pkg/port/iscsit/packet.go b/pkg/port/iscsit/cmd.go similarity index 57% rename from pkg/port/iscsit/packet.go rename to pkg/port/iscsit/cmd.go index e502051..69b674a 100644 --- a/pkg/port/iscsit/packet.go +++ b/pkg/port/iscsit/cmd.go @@ -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() +} diff --git a/pkg/port/iscsit/iscsit.go b/pkg/port/iscsit/iscsit.go index 3165bb8..c951234 100644 --- a/pkg/port/iscsit/iscsit.go +++ b/pkg/port/iscsit/iscsit.go @@ -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 +} diff --git a/pkg/port/iscsit/login.go b/pkg/port/iscsit/login.go index b30d08e..3dec0d8 100644 --- a/pkg/port/iscsit/login.go +++ b/pkg/port/iscsit/login.go @@ -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 diff --git a/pkg/port/iscsit/logout.go b/pkg/port/iscsit/logout.go index a28e48c..3ce91f9 100644 --- a/pkg/port/iscsit/logout.go +++ b/pkg/port/iscsit/logout.go @@ -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) diff --git a/pkg/port/iscsit/session.go b/pkg/port/iscsit/session.go index 8705f11..b043bbb 100644 --- a/pkg/port/iscsit/session.go +++ b/pkg/port/iscsit/session.go @@ -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 } diff --git a/pkg/scsi/backingstore.go b/pkg/scsi/backingstore.go index 1d9f8fc..4e585bd 100644 --- a/pkg/scsi/backingstore.go +++ b/pkg/scsi/backingstore.go @@ -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 } diff --git a/pkg/scsi/backingstore/null.go b/pkg/scsi/backingstore/null.go index c2fb4bb..afb7837 100644 --- a/pkg/scsi/backingstore/null.go +++ b/pkg/scsi/backingstore/null.go @@ -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 } diff --git a/pkg/scsi/cmd.go b/pkg/scsi/cmd.go index 0c80d5d..e50fa3a 100644 --- a/pkg/scsi/cmd.go +++ b/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) } diff --git a/pkg/scsi/drivers.go b/pkg/scsi/drivers.go index 61c2428..fc5ce9a 100644 --- a/pkg/scsi/drivers.go +++ b/pkg/scsi/drivers.go @@ -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 -} diff --git a/pkg/scsi/lun.go b/pkg/scsi/lun.go index ce6724b..2856a32 100644 --- a/pkg/scsi/lun.go +++ b/pkg/scsi/lun.go @@ -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 } diff --git a/pkg/scsi/sbc.go b/pkg/scsi/sbc.go index 721244f..f9caa98 100644 --- a/pkg/scsi/sbc.go +++ b/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<