init commit
This commit is contained in:
18
pkg/apiserver/api_installer.go
Normal file
18
pkg/apiserver/api_installer.go
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
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 apiserver contains the code that provides a rest.ful api service.
|
||||
package apiserver
|
||||
18
pkg/apiserver/apiserver.go
Normal file
18
pkg/apiserver/apiserver.go
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
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 apiserver contains the code that provides a rest.ful api service.
|
||||
package apiserver
|
||||
18
pkg/apiserver/doc.go
Normal file
18
pkg/apiserver/doc.go
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
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 apiserver contains the code that provides a rest.ful api service.
|
||||
package apiserver
|
||||
17
pkg/apiserver/handlers.go
Normal file
17
pkg/apiserver/handlers.go
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
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 apiserver
|
||||
24
pkg/port/iscsit/auth.go
Normal file
24
pkg/port/iscsit/auth.go
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
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
|
||||
|
||||
type AuthMethod int
|
||||
|
||||
const (
|
||||
AuthNone = iota
|
||||
AuthChap
|
||||
)
|
||||
84
pkg/port/iscsit/iscsit.go
Normal file
84
pkg/port/iscsit/iscsit.go
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// iSCSI Target Driver
|
||||
package iscsit
|
||||
|
||||
type ISCSIDiscoveryMethod string
|
||||
|
||||
var (
|
||||
ISCSIDiscoverySendTargets ISCSIDiscoveryMethod = "sendtargets"
|
||||
ISCSIDiscoveryStaticConfig ISCSIDiscoveryMethod = "static"
|
||||
ISCSIDiscoveryISNS ISCSIDiscoveryMethod = "isns"
|
||||
)
|
||||
|
||||
type ISCSIRedirectInfo struct {
|
||||
Address string
|
||||
Port int
|
||||
Reason uint8
|
||||
Callback string
|
||||
}
|
||||
|
||||
type ISCSITarget struct {
|
||||
Sessions []*ISCSISession
|
||||
SessionParam []ISCSISessionParam
|
||||
TID int
|
||||
Alias string
|
||||
MaxSessions int
|
||||
RedirectInfo ISCSIRedirectInfo
|
||||
Rdma int
|
||||
NopInterval int
|
||||
NopCount int
|
||||
}
|
||||
|
||||
type ISCSITargetDriver struct {
|
||||
SCSITargetDriver
|
||||
}
|
||||
|
||||
func (tgt *ISCSITargetDriver) Init() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tgt *ISCSITargetDriver) Exit() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tgt *ISCSITargetDriver) CreateTarget(target *SCSITarget) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tgt *ISCSITargetDriver) DestroyTarget(target *SCSITarget) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tgt *ISCSITargetDriver) CreatePortal(name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tgt *ISCSITargetDriver) DestroyPortal(name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tgt *ISCSITargetDriver) CreateLu(lu *SCSILu) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tgt *ISCSITargetDriver) GetLun(lun uint8) (uint64, error) {
|
||||
return 0, nil
|
||||
}
|
||||
func (tgt *ISCSITargetDriver) CommandNotify(nid uint64, result int, cmd *SCSICommand) error {
|
||||
return nil
|
||||
}
|
||||
85
pkg/port/iscsit/login.go
Normal file
85
pkg/port/iscsit/login.go
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
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 {
|
||||
// rfc7143 11.13
|
||||
buf := &bytes.Buffer{}
|
||||
// byte 0
|
||||
buf.WriteByte(byte(OpLoginResp))
|
||||
var b byte
|
||||
if m.Transit {
|
||||
b |= 0x80
|
||||
}
|
||||
if m.Cont {
|
||||
b |= 0x40
|
||||
}
|
||||
b |= byte(m.CSG&0xff) << 2
|
||||
b |= byte(m.NSG & 0xff)
|
||||
// byte 1
|
||||
buf.WriteByte(b)
|
||||
|
||||
b = 0
|
||||
buf.WriteByte(b) // version-max
|
||||
buf.WriteByte(b) // version-active
|
||||
buf.WriteByte(b) // ahsLen
|
||||
buf.Write(MarshalUint64(uint64(len(m.RawData)))[5:]) // data segment length, no padding
|
||||
buf.Write(MarshalUint64(m.ISID)[2:])
|
||||
buf.Write(MarshalUint64(uint64(m.TSIH))[6:])
|
||||
buf.Write(MarshalUint64(uint64(m.TaskTag))[4:])
|
||||
buf.WriteByte(b)
|
||||
buf.WriteByte(b)
|
||||
buf.WriteByte(b)
|
||||
buf.WriteByte(b) // "reserved"
|
||||
buf.Write(MarshalUint64(uint64(m.StatSN))[4:])
|
||||
buf.Write(MarshalUint64(uint64(m.ExpCmdSN))[4:])
|
||||
buf.Write(MarshalUint64(uint64(m.MaxCmdSN))[4:])
|
||||
buf.WriteByte(byte(m.StatusClass))
|
||||
buf.WriteByte(byte(m.StatusDetail))
|
||||
buf.WriteByte(b)
|
||||
buf.WriteByte(b) // "reserved"
|
||||
var bs [8]byte
|
||||
buf.Write(bs[:])
|
||||
rd := m.RawData
|
||||
for len(rd)%4 != 0 {
|
||||
rd = append(rd, 0)
|
||||
}
|
||||
buf.Write(rd)
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
type Stage int
|
||||
|
||||
const (
|
||||
SecurityNegotiation Stage = 0
|
||||
LoginOperationalNegotiation = 1
|
||||
FullFeaturePhase = 3
|
||||
)
|
||||
|
||||
func (s Stage) String() string {
|
||||
switch s {
|
||||
case SecurityNegotiation:
|
||||
return "Security Negotiation"
|
||||
case LoginOperationalNegotiation:
|
||||
return "Login Operational Negotiation"
|
||||
case FullFeaturePhase:
|
||||
return "Full Feature Phase"
|
||||
}
|
||||
return "Unknown Stage"
|
||||
}
|
||||
41
pkg/port/iscsit/logout.go
Normal file
41
pkg/port/iscsit/logout.go
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
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 {
|
||||
buf := &bytes.Buffer{}
|
||||
buf.WriteByte(byte(OpLogoutResp))
|
||||
buf.WriteByte(0x80)
|
||||
buf.WriteByte(0x00) // response
|
||||
buf.WriteByte(0x00)
|
||||
for i := 4; i < 16; i++ {
|
||||
buf.WriteByte(0x00)
|
||||
}
|
||||
buf.Write(MarshalUint64(uint64(m.TaskTag))[4:])
|
||||
for i := 20; i < 24; 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 := 36; i < 48; i++ {
|
||||
buf.WriteByte(0x00)
|
||||
}
|
||||
return buf.Bytes()
|
||||
}
|
||||
276
pkg/port/iscsit/packet.go
Normal file
276
pkg/port/iscsit/packet.go
Normal file
@@ -0,0 +1,276 @@
|
||||
/*
|
||||
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 (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type OpCode int
|
||||
|
||||
const (
|
||||
// Defined on the initiator.
|
||||
OpNoopOut OpCode = 0x00
|
||||
OpSCSICmd = 0x01
|
||||
OpSCSITaskReq = 0x02
|
||||
OpLoginReq = 0x03
|
||||
OpTextReq = 0x04
|
||||
OpSCSIOut = 0x05
|
||||
OpLogoutReq = 0x06
|
||||
OpSNACKReq = 0x10
|
||||
// Defined on the target.
|
||||
OpNoopIn OpCode = 0x20
|
||||
OpSCSIResp = 0x21
|
||||
OpSCSITaskResp = 0x22
|
||||
OpLoginResp = 0x23
|
||||
OpTextResp = 0x24
|
||||
OpSCSIIn = 0x25
|
||||
OpLogoutResp = 0x26
|
||||
OpReady = 0x31
|
||||
OpAsync = 0x32
|
||||
OpReject = 0x3f
|
||||
)
|
||||
|
||||
var opCodeMap = map[OpCode]string{
|
||||
OpNoopOut: "NOP-Out",
|
||||
OpSCSICmd: "SCSI Command",
|
||||
OpSCSITaskReq: "SCSI Task Management FunctionRequest",
|
||||
OpLoginReq: "Login Request",
|
||||
OpTextReq: "Text Request",
|
||||
OpSCSIOut: "SCSI Data-Out (write)",
|
||||
OpLogoutReq: "Logout Request",
|
||||
OpSNACKReq: "SNACK Request",
|
||||
OpNoopIn: "NOP-In",
|
||||
OpSCSIResp: "SCSI Response",
|
||||
OpSCSITaskResp: "SCSI Task Management Function Response",
|
||||
OpLoginResp: "Login Response",
|
||||
OpTextResp: "Text Response",
|
||||
OpSCSIIn: "SCSI Data-In (read)",
|
||||
OpLogoutResp: "Logout Response",
|
||||
OpReady: "Ready To Transfer (R2T)",
|
||||
OpAsync: "Asynchronous Message",
|
||||
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 {
|
||||
OpCode OpCode
|
||||
RawHeader []byte
|
||||
DataLen int
|
||||
RawData []byte
|
||||
Final bool
|
||||
Immediate bool
|
||||
TaskTag uint32
|
||||
ExpCmdSN, MaxCmdSN uint32
|
||||
AHSLen int
|
||||
|
||||
ConnID uint16 // Connection ID.
|
||||
CmdSN uint32 // Command serial number.
|
||||
ExpStatSN uint32 // Expected status serial.
|
||||
|
||||
Read, Write bool
|
||||
LUN uint8
|
||||
Transit bool // Transit bit.
|
||||
Cont bool // Continue bit.
|
||||
CSG, NSG Stage // Current Stage, Next Stage.
|
||||
ISID uint64 // Initiator part of the SSID.
|
||||
TSIH uint16 // Target-assigned Session Identifying Handle.
|
||||
StatSN uint32 // Status serial number.
|
||||
|
||||
// For login response.
|
||||
StatusClass uint8
|
||||
StatusDetail uint8
|
||||
|
||||
// SCSI commands
|
||||
ExpectedDataLen uint32
|
||||
CDB []byte
|
||||
Status Status
|
||||
SCSIResponse Response
|
||||
|
||||
// Data-In
|
||||
HasStatus bool
|
||||
DataSN uint32
|
||||
BufferOffset uint32
|
||||
}
|
||||
|
||||
func (m *Message) Bytes() []byte {
|
||||
switch m.OpCode {
|
||||
case OpLoginResp:
|
||||
return m.loginRespBytes()
|
||||
case OpLogoutResp:
|
||||
return m.logoutRespBytes()
|
||||
case OpSCSIResp:
|
||||
return m.scsiCmdRespBytes()
|
||||
case OpSCSIIn:
|
||||
return m.dataInBytes()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Message) String() string {
|
||||
var s []string
|
||||
s = append(s, fmt.Sprintf("Op: %v", 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))
|
||||
s = append(s, fmt.Sprintf("Task Tag = %x", m.TaskTag))
|
||||
s = append(s, fmt.Sprintf("AHS Length = %d", m.AHSLen))
|
||||
switch m.OpCode {
|
||||
case OpLoginReq:
|
||||
s = append(s, fmt.Sprintf("ISID = %x", m.ISID))
|
||||
s = append(s, fmt.Sprintf("Transit = %v", m.Transit))
|
||||
s = append(s, fmt.Sprintf("Continue = %v", m.Cont))
|
||||
s = append(s, fmt.Sprintf("Current Stage = %v", m.CSG))
|
||||
s = append(s, fmt.Sprintf("Next Stage = %v", m.NSG))
|
||||
case OpLoginResp:
|
||||
s = append(s, fmt.Sprintf("ISID = %x", m.ISID))
|
||||
s = append(s, fmt.Sprintf("Transit = %v", m.Transit))
|
||||
s = append(s, fmt.Sprintf("Continue = %v", m.Cont))
|
||||
s = append(s, fmt.Sprintf("Current Stage = %v", m.CSG))
|
||||
s = append(s, fmt.Sprintf("Next Stage = %v", m.NSG))
|
||||
s = append(s, fmt.Sprintf("Status Class = %d", m.StatusClass))
|
||||
s = append(s, fmt.Sprintf("Status Detail = %d", m.StatusDetail))
|
||||
case OpSCSICmd:
|
||||
s = append(s, fmt.Sprintf("LUN = %d", m.LUN))
|
||||
s = append(s, fmt.Sprintf("ExpectedDataLen = %d", m.ExpectedDataLen))
|
||||
s = append(s, fmt.Sprintf("CmdSN = %d", m.CmdSN))
|
||||
s = append(s, fmt.Sprintf("ExpStatSN = %d", m.ExpStatSN))
|
||||
s = append(s, fmt.Sprintf("Read = %v", m.Read))
|
||||
s = append(s, fmt.Sprintf("Write = %v", m.Write))
|
||||
s = append(s, fmt.Sprintf("CDB = %x", m.CDB))
|
||||
case OpSCSIResp:
|
||||
s = append(s, fmt.Sprintf("StatSN = %d", m.StatSN))
|
||||
s = append(s, fmt.Sprintf("ExpCmdSN = %d", m.ExpCmdSN))
|
||||
s = append(s, fmt.Sprintf("MaxCmdSN = %d", m.MaxCmdSN))
|
||||
}
|
||||
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 {
|
||||
var out uint64
|
||||
for i := 0; i < len(data); i++ {
|
||||
out += uint64(data[len(data)-i-1]) << uint(8*i)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func MarshalUint64(i uint64) []byte {
|
||||
var data []byte
|
||||
for j := 0; j < 8; j++ {
|
||||
b := byte(i >> uint(8*(7-j)) & 0xff)
|
||||
data = append(data, b)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func parseHeader(data []byte) (*Message, error) {
|
||||
if len(data) != 48 {
|
||||
return nil, fmt.Errorf("garbled header")
|
||||
}
|
||||
// TODO: sync.Pool
|
||||
m := &Message{}
|
||||
m.Immediate = 0x40&data[0] == 0x40
|
||||
m.OpCode = OpCode(data[0] & 0x3f)
|
||||
m.Final = 0x80&data[1] == 0x80
|
||||
m.AHSLen = int(data[4]) * 4
|
||||
m.DataLen = int(ParseUint(data[5:8]))
|
||||
m.TaskTag = uint32(ParseUint(data[16:20]))
|
||||
switch m.OpCode {
|
||||
case OpSCSICmd:
|
||||
m.LUN = uint8(data[9])
|
||||
m.ExpectedDataLen = uint32(ParseUint(data[20:24]))
|
||||
m.CmdSN = uint32(ParseUint(data[24:28]))
|
||||
m.Read = data[1]&0x40 == 0x40
|
||||
m.Write = data[1]&0x20 == 0x20
|
||||
m.CDB = data[32:48]
|
||||
m.ExpStatSN = uint32(ParseUint(data[28:32]))
|
||||
case OpSCSIResp:
|
||||
case OpLoginReq:
|
||||
m.Transit = m.Final
|
||||
m.Cont = data[1]&0x40 == 0x40
|
||||
if m.Cont && m.Transit {
|
||||
// rfc7143 11.12.2
|
||||
return nil, fmt.Errorf("transit and continue bits set in same login request")
|
||||
}
|
||||
m.CSG = Stage(data[1]&0xc) >> 2
|
||||
m.NSG = Stage(data[1] & 0x3)
|
||||
m.ISID = uint64(ParseUint(data[8:14]))
|
||||
m.TSIH = uint16(ParseUint(data[14:16]))
|
||||
m.ConnID = uint16(ParseUint(data[20:22]))
|
||||
m.CmdSN = uint32(ParseUint(data[24:28]))
|
||||
m.ExpStatSN = uint32(ParseUint(data[28:32]))
|
||||
case OpLoginResp:
|
||||
m.Transit = m.Final
|
||||
m.Cont = data[1]&0x40 == 0x40
|
||||
if m.Cont && m.Transit {
|
||||
// rfc7143 11.12.2
|
||||
return nil, fmt.Errorf("transit and continue bits set in same login request")
|
||||
}
|
||||
m.CSG = Stage(data[1]&0xc) >> 2
|
||||
m.NSG = Stage(data[1] & 0x3)
|
||||
m.StatSN = uint32(ParseUint(data[24:28]))
|
||||
m.ExpCmdSN = uint32(ParseUint(data[28:32]))
|
||||
m.MaxCmdSN = uint32(ParseUint(data[32:36]))
|
||||
m.StatusClass = uint8(data[36])
|
||||
m.StatusDetail = uint8(data[37])
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
25
pkg/port/iscsit/portal.go
Normal file
25
pkg/port/iscsit/portal.go
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
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
|
||||
|
||||
type ISCSIPortal struct {
|
||||
Address string
|
||||
Port int
|
||||
Tpgt int
|
||||
Fd int
|
||||
Af int
|
||||
}
|
||||
84
pkg/port/iscsit/session.go
Normal file
84
pkg/port/iscsit/session.go
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
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 "crypto/rand"
|
||||
|
||||
type ISCSISessionParam struct {
|
||||
State int
|
||||
Value uint
|
||||
}
|
||||
|
||||
// Session is an iSCSI session.
|
||||
type ISCSISession struct {
|
||||
Refcount int
|
||||
Initiator string
|
||||
InitiatorAlias string
|
||||
Target *ISCSITarget
|
||||
Isid uint64
|
||||
Tsih uint16
|
||||
// only one connection per session
|
||||
Connections []*ISCSIConnection
|
||||
Commands []*ISCSICommand
|
||||
PendingCommands []*ISCSICommand
|
||||
ExpectionCommandSN uint32
|
||||
MaxQueueCommand uint32
|
||||
SessionParam []ISCSISessionParam
|
||||
Info string
|
||||
Rdma int
|
||||
}
|
||||
|
||||
type ISCSIPdu struct {
|
||||
Bhs ISCSIHeader
|
||||
AhsSize uint
|
||||
DataSize uint
|
||||
}
|
||||
|
||||
type ISCSIConnection struct {
|
||||
State int
|
||||
RxIostate int
|
||||
TxIostate int
|
||||
Refcount int
|
||||
|
||||
Session *ISCSISession
|
||||
|
||||
TID int
|
||||
CID int
|
||||
Auth AuthMethod
|
||||
StatSN uint32
|
||||
ExpectionStatSN uint32
|
||||
CommandSN uint32
|
||||
ExpectionCommandSN uint32
|
||||
MaxCommandSN uint32
|
||||
Request ISCSIPdu
|
||||
Response ISCSIPdu
|
||||
}
|
||||
|
||||
// New creates a new session.
|
||||
func NewISCSISession() (*ISCSISession, error) {
|
||||
var tsih uint16
|
||||
b := make([]byte, 2)
|
||||
if _, err := rand.Read(b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tsih += uint16(b[0]) << 8
|
||||
tsih += uint16(b[1])
|
||||
|
||||
return &Session{
|
||||
Tsih: tsih,
|
||||
}, nil
|
||||
}
|
||||
76
pkg/scsi/backingstore.go
Normal file
76
pkg/scsi/backingstore.go
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
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 scsi
|
||||
|
||||
import "fmt"
|
||||
|
||||
type BaseBackingStore struct {
|
||||
Name string
|
||||
DataSize int
|
||||
OflagsSupported int
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
type BackingStoreFunc func() (BackingStore, error)
|
||||
|
||||
var registeredPlugins = map[name](BackingStoreFunc){}
|
||||
|
||||
func RegisterBackingStore(name string, f BackingStoreFunc) {
|
||||
registeredPlugins[name] = f
|
||||
}
|
||||
|
||||
func NewBackingStore(name string) (BackingStore, error) {
|
||||
if name == "" {
|
||||
return nil, nil
|
||||
}
|
||||
f, ok := registeredPlugins[name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("BackingStore %s is not found.", name)
|
||||
}
|
||||
return f()
|
||||
}
|
||||
|
||||
type fakeBackingStore struct {
|
||||
BaseBackingStore
|
||||
}
|
||||
|
||||
func (fake *fakeBackingStore) Open(dev *SCSILu, path string, fd *int, size *uint64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fake *fakeBackingStore) Close(dev *SCSILu) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fake *fakeBackingStore) Init(dev *SCSILu, Opts string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fake *fakeBackingStore) Exit(dev *SCSILu) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fake *fakeBackingStore) CommandSubmit(cmd *SCSICommand) error {
|
||||
return nil
|
||||
}
|
||||
55
pkg/scsi/backingstore/common.go
Normal file
55
pkg/scsi/backingstore/common.go
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
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 backingstore
|
||||
|
||||
import "github.com/gostor/gotgt/pkg/scsi"
|
||||
|
||||
func init() {
|
||||
scsi.RegisterBackingStore("file", new)
|
||||
}
|
||||
|
||||
type FileBackingStore struct {
|
||||
BaseBackingStore
|
||||
}
|
||||
|
||||
func new() (scsi.BackingStore, error) {
|
||||
return NullBackingStore{
|
||||
Name: "file",
|
||||
DataSize: 0,
|
||||
OflagsSupported: 0,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (bs *FileBackingStore) Open(dev *SCSILu, path string, fd *int, size *uint64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bs *FileBackingStore) Close(dev *SCSILu) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bs *FileBackingStore) Init(dev *SCSILu, Opts string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bs *FileBackingStore) Exit(dev *SCSILu) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bs *FileBackingStore) CommandSubmit(cmd *SCSICommand) error {
|
||||
return nil
|
||||
}
|
||||
55
pkg/scsi/backingstore/null.go
Normal file
55
pkg/scsi/backingstore/null.go
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
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 backingstore
|
||||
|
||||
import "github.com/gostor/gotgt/pkg/scsi"
|
||||
|
||||
func init() {
|
||||
scsi.RegisterBackingStore("null", new)
|
||||
}
|
||||
|
||||
type NullBackingStore struct {
|
||||
BaseBackingStore
|
||||
}
|
||||
|
||||
func new() (scsi.BackingStore, error) {
|
||||
return NullBackingStore{
|
||||
Name: "null",
|
||||
DataSize: 0,
|
||||
OflagsSupported: 0,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (bs *NullBackingStore) Open(dev *SCSILu, path string, fd *int, size *uint64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bs *NullBackingStore) Close(dev *SCSILu) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bs *NullBackingStore) Init(dev *SCSILu, Opts string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bs *NullBackingStore) Exit(dev *SCSILu) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bs *NullBackingStore) CommandSubmit(cmd *SCSICommand) error {
|
||||
return nil
|
||||
}
|
||||
192
pkg/scsi/cmd.go
Normal file
192
pkg/scsi/cmd.go
Normal file
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
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 scsi
|
||||
|
||||
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
|
||||
|
||||
var (
|
||||
/* PERSISTENT_RESERVE_IN service action codes */
|
||||
PR_IN_READ_KEYS SCSIPRServiceAction = 0x00
|
||||
PR_IN_READ_RESERVATION SCSIPRServiceAction = 0x01
|
||||
PR_IN_REPORT_CAPABILITIES SCSIPRServiceAction = 0x02
|
||||
PR_IN_READ_FULL_STATUS SCSIPRServiceAction = 0x03
|
||||
|
||||
/* PERSISTENT_RESERVE_OUT service action codes */
|
||||
PR_OUT_REGISTER SCSIPRServiceAction = 0x00
|
||||
PR_OUT_RESERVE SCSIPRServiceAction = 0x01
|
||||
PR_OUT_RELEASE SCSIPRServiceAction = 0x02
|
||||
PR_OUT_CLEAR SCSIPRServiceAction = 0x03
|
||||
PR_OUT_PREEMPT SCSIPRServiceAction = 0x04
|
||||
PR_OUT_PREEMPT_AND_ABORT SCSIPRServiceAction = 0x05
|
||||
PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY SCSIPRServiceAction = 0x06
|
||||
PR_OUT_REGISTER_AND_MOVE SCSIPRServiceAction = 0x07
|
||||
|
||||
/* Persistent Reservation scope */
|
||||
PR_LU_SCOPE byte = 0x00
|
||||
|
||||
/* Persistent Reservation Type Mask format */
|
||||
PR_TYPE_WRITE_EXCLUSIVE SCSIPRType = 0x01
|
||||
PR_TYPE_EXCLUSIVE_ACCESS SCSIPRType = 0x03
|
||||
PR_TYPE_WRITE_EXCLUSIVE_REGONLY SCSIPRType = 0x05
|
||||
PR_TYPE_EXCLUSIVE_ACCESS_REGONLY SCSIPRType = 0x06
|
||||
PR_TYPE_WRITE_EXCLUSIVE_ALLREG SCSIPRType = 0x07
|
||||
PR_TYPE_EXCLUSIVE_ACCESS_ALLREG SCSIPRType = 0x08
|
||||
)
|
||||
|
||||
type SCSIDataDirection int
|
||||
|
||||
const (
|
||||
SCSIDataNone = iota
|
||||
SCSIDataWrite
|
||||
SCSIDataRead
|
||||
SCSIDataBidirection
|
||||
)
|
||||
|
||||
type SCSIDataBuffer struct {
|
||||
Buffer uint64
|
||||
Length uint64
|
||||
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 *[]byte
|
||||
SCBLength int
|
||||
Lun []uint8
|
||||
Attribute int
|
||||
Tag uint64
|
||||
Result int
|
||||
SenseBuffer []byte
|
||||
SenseLength int
|
||||
}
|
||||
89
pkg/scsi/drivers.go
Normal file
89
pkg/scsi/drivers.go
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// Target Driver Interface
|
||||
package scsi
|
||||
|
||||
var 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
|
||||
|
||||
GetLun(lun uint8) (uint64, error)
|
||||
CommandNotify(nid uint64, result int, cmd *SCSICommand) error
|
||||
}
|
||||
|
||||
var fakeSCSITargetDriver 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
|
||||
}
|
||||
123
pkg/scsi/error.go
Normal file
123
pkg/scsi/error.go
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
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 scsi
|
||||
|
||||
type SCSIError byte
|
||||
|
||||
var (
|
||||
NO_SENSE SCSIError = 0x00
|
||||
RECOVERED_ERROR SCSIError = 0x01
|
||||
NOT_READY SCSIError = 0x02
|
||||
MEDIUM_ERROR SCSIError = 0x03
|
||||
HARDWARE_ERROR SCSIError = 0x04
|
||||
ILLEGAL_REQUEST SCSIError = 0x05
|
||||
UNIT_ATTENTION SCSIError = 0x06
|
||||
DATA_PROTECT SCSIError = 0x07
|
||||
BLANK_CHECK SCSIError = 0x08
|
||||
COPY_ABORTED SCSIError = 0x0a
|
||||
ABORTED_COMMAND SCSIError = 0x0b
|
||||
VOLUME_OVERFLOW SCSIError = 0x0d
|
||||
MISCOMPARE SCSIError = 0x0e
|
||||
)
|
||||
|
||||
type SCSISubError uint16
|
||||
|
||||
var (
|
||||
/* Key 0: No Sense Errors */
|
||||
NO_ADDITIONAL_SENSE SCSISubError = 0x0000
|
||||
ASC_MARK SCSISubError = 0x0001
|
||||
ASC_EOM SCSISubError = 0x0002
|
||||
ASC_BOM SCSISubError = 0x0004
|
||||
ASC_END_OF_DATA SCSISubError = 0x0005
|
||||
ASC_OP_IN_PROGRESS SCSISubError = 0x0016
|
||||
ASC_DRIVE_REQUIRES_CLEANING SCSISubError = 0x8282
|
||||
|
||||
/* Key 1: Recovered Errors */
|
||||
ASC_WRITE_ERROR SCSISubError = 0x0c00
|
||||
ASC_READ_ERROR SCSISubError = 0x1100
|
||||
ASC_RECOVERED_WITH_RETRYS SCSISubError = 0x1701
|
||||
ASC_MEDIA_LOAD_EJECT_ERROR SCSISubError = 0x5300
|
||||
ASC_FAILURE_PREDICTION SCSISubError = 0x5d00
|
||||
|
||||
/* Key 2: Not ready */
|
||||
ASC_CAUSE_NOT_REPORTABLE SCSISubError = 0x0400
|
||||
ASC_BECOMING_READY SCSISubError = 0x0401
|
||||
ASC_INITIALIZING_REQUIRED SCSISubError = 0x0402
|
||||
ASC_CLEANING_CART_INSTALLED SCSISubError = 0x3003
|
||||
ASC_CLEANING_FAILURE SCSISubError = 0x3007
|
||||
ASC_MEDIUM_NOT_PRESENT SCSISubError = 0x3a00
|
||||
ASC_LOGICAL_UNIT_NOT_CONFIG SCSISubError = 0x3e00
|
||||
|
||||
/* Key 3: Medium Errors */
|
||||
ASC_WRITE_ERROR SCSISubError = 0x0c00
|
||||
ASC_UNRECOVERED_READ SCSISubError = 0x1100
|
||||
ASC_RECORDED_ENTITY_NOT_FOUND SCSISubError = 0x1400
|
||||
ASC_UNKNOWN_FORMAT SCSISubError = 0x3001
|
||||
ASC_IMCOMPATIBLE_FORMAT SCSISubError = 0x3002
|
||||
ASC_MEDIUM_FORMAT_CORRUPT SCSISubError = 0x3100
|
||||
ASC_SEQUENTIAL_POSITION_ERR SCSISubError = 0x3b00
|
||||
ASC_WRITE_APPEND_ERR SCSISubError = 0x5000
|
||||
ASC_CARTRIDGE_FAULT SCSISubError = 0x5200
|
||||
ASC_MEDIA_LOAD_OR_EJECT_FAILED SCSISubError = 0x5300
|
||||
|
||||
/* Key 4: Hardware Failure */
|
||||
ASC_COMPRESSION_CHECK SCSISubError = 0x0c04
|
||||
ASC_DECOMPRESSION_CRC SCSISubError = 0x110d
|
||||
ASC_MECHANICAL_POSITIONING_ERROR SCSISubError = 0x1501
|
||||
ASC_MANUAL_INTERVENTION_REQ SCSISubError = 0x0403
|
||||
ASC_HARDWARE_FAILURE SCSISubError = 0x4000
|
||||
ASC_INTERNAL_TGT_FAILURE SCSISubError = 0x4400
|
||||
ASC_ERASE_FAILURE SCSISubError = 0x5100
|
||||
|
||||
/* Key 5: Illegal Request */
|
||||
ASC_PARAMETER_LIST_LENGTH_ERR SCSISubError = 0x1a00
|
||||
ASC_INVALID_OP_CODE SCSISubError = 0x2000
|
||||
ASC_LBA_OUT_OF_RANGE SCSISubError = 0x2100
|
||||
ASC_INVALID_FIELD_IN_CDB SCSISubError = 0x2400
|
||||
ASC_LUN_NOT_SUPPORTED SCSISubError = 0x2500
|
||||
ASC_INVALID_FIELD_IN_PARMS SCSISubError = 0x2600
|
||||
ASC_INVALID_RELEASE_OF_PERSISTENT_RESERVATION SCSISubError = 0x2604
|
||||
ASC_INCOMPATIBLE_FORMAT SCSISubError = 0x3005
|
||||
ASC_SAVING_PARMS_UNSUP SCSISubError = 0x3900
|
||||
ASC_MEDIUM_DEST_FULL SCSISubError = 0x3b0d
|
||||
ASC_MEDIUM_SRC_EMPTY SCSISubError = 0x3b0e
|
||||
ASC_POSITION_PAST_BOM SCSISubError = 0x3b0c
|
||||
ASC_MEDIUM_REMOVAL_PREVENTED SCSISubError = 0x5302
|
||||
ASC_INSUFFICENT_REGISTRATION_RESOURCES SCSISubError = 0x5504
|
||||
ASC_BAD_MICROCODE_DETECTED SCSISubError = 0x8283
|
||||
|
||||
/* Key 6: Unit Attention */
|
||||
ASC_NOT_READY_TO_TRANSITION SCSISubError = 0x2800
|
||||
ASC_POWERON_RESET SCSISubError = 0x2900
|
||||
ASC_I_T_NEXUS_LOSS_OCCURRED SCSISubError = 0x2907
|
||||
ASC_MODE_PARAMETERS_CHANGED SCSISubError = 0x2a01
|
||||
ASC_RESERVATIONS_PREEMPTED SCSISubError = 0x2a03
|
||||
ASC_RESERVATIONS_RELEASED SCSISubError = 0x2a04
|
||||
ASC_INSUFFICIENT_TIME_FOR_OPERATION SCSISubError = 0x2e00
|
||||
ASC_CMDS_CLEARED_BY_ANOTHER_INI SCSISubError = 0x2f00
|
||||
ASC_MICROCODE_DOWNLOADED SCSISubError = 0x3f01
|
||||
ASC_INQUIRY_DATA_HAS_CHANGED SCSISubError = 0x3f03
|
||||
ASC_REPORTED_LUNS_DATA_HAS_CHANGED SCSISubError = 0x3f0e
|
||||
ASC_FAILURE_PREDICTION_FALSE SCSISubError = 0x5dff
|
||||
|
||||
/* Data Protect */
|
||||
ASC_WRITE_PROTECT SCSISubError = 0x2700
|
||||
ASC_MEDIUM_OVERWRITE_ATTEMPTED SCSISubError = 0x300c
|
||||
|
||||
/* Miscompare */
|
||||
ASC_MISCOMPARE_DURING_VERIFY_OPERATION SCSISubError = 0x1d00
|
||||
)
|
||||
29
pkg/scsi/lun.go
Normal file
29
pkg/scsi/lun.go
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
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 scsi
|
||||
|
||||
type SCSILu struct {
|
||||
FD int
|
||||
Address uint64
|
||||
Size uint64
|
||||
Lun uint64
|
||||
Path string
|
||||
BsoFlags int
|
||||
BlockShift uint
|
||||
ReserveID uint64
|
||||
Target *SCSITarget
|
||||
}
|
||||
18
pkg/scsi/sbc.go
Normal file
18
pkg/scsi/sbc.go
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// SCSI block command processing
|
||||
package scsi
|
||||
60
pkg/scsi/scsi.go
Normal file
60
pkg/scsi/scsi.go
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
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 scsi
|
||||
|
||||
var (
|
||||
DefaultBlockShift int = 9
|
||||
DefaultSenseBufferSize int = 252
|
||||
)
|
||||
|
||||
type SAMStat byte
|
||||
type SCSIDeviceType byte
|
||||
|
||||
var (
|
||||
SAM_STAT_GOOD SAMStat = 0x00
|
||||
SAM_STAT_CHECK_CONDITION SAMStat = 0x02
|
||||
SAM_STAT_CONDITION_MET SAMStat = 0x04
|
||||
SAM_STAT_BUSY SAMStat = 0x08
|
||||
SAM_STAT_INTERMEDIATE SAMStat = 0x10
|
||||
SAM_STAT_INTERMEDIATE_CONDITION_MET SAMStat = 0x14
|
||||
SAM_STAT_RESERVATION_CONFLICT SAMStat = 0x18
|
||||
SAM_STAT_COMMAND_TERMINATED SAMStat = 0x22
|
||||
SAM_STAT_TASK_SET_FULL SAMStat = 0x28
|
||||
SAM_STAT_ACA_ACTIVE SAMStat = 0x30
|
||||
SAM_STAT_TASK_ABORTED SAMStat = 0x40
|
||||
)
|
||||
|
||||
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
|
||||
)
|
||||
103
pkg/scsi/spc.go
Normal file
103
pkg/scsi/spc.go
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// SCSI primary command processing
|
||||
package scsi
|
||||
|
||||
/*
|
||||
* Protocol Identifier Values
|
||||
*
|
||||
* 0 Fibre Channel (FCP-2)
|
||||
* 1 Parallel SCSI (SPI-5)
|
||||
* 2 SSA (SSA-S3P)
|
||||
* 3 IEEE 1394 (SBP-3)
|
||||
* 4 SCSI Remote Direct Memory Access (SRP)
|
||||
* 5 iSCSI
|
||||
* 6 SAS Serial SCSI Protocol (SAS)
|
||||
* 7 Automation/Drive Interface (ADT)
|
||||
* 8 AT Attachment Interface (ATA/ATAPI-7)
|
||||
*/
|
||||
type ProtocolIdentifier int
|
||||
|
||||
var (
|
||||
PIV_FCP ProtocolIdentifier = iota
|
||||
PIV_SPI ProtocolIdentifier
|
||||
PIV_S3P ProtocolIdentifier
|
||||
PIV_SBP ProtocolIdentifier
|
||||
PIV_SRP ProtocolIdentifier
|
||||
PIV_ISCSI ProtocolIdentifier
|
||||
PIV_SAS ProtocolIdentifier
|
||||
PIV_ADT ProtocolIdentifier
|
||||
PIV_ATA ProtocolIdentifier
|
||||
)
|
||||
|
||||
/*
|
||||
* Code Set
|
||||
*
|
||||
* 1 - Designator fild contains binary values
|
||||
* 2 - Designator field contains ASCII printable chars
|
||||
* 3 - Designaotor field contains UTF-8
|
||||
*/
|
||||
type CodeSet int
|
||||
|
||||
var (
|
||||
INQ_CODE_BIN CodeSet = 1
|
||||
INQ_CODE_ASCII CodeSet = 2
|
||||
INQ_CODE_UTF8 CodeSet = 3
|
||||
)
|
||||
|
||||
/*
|
||||
* Association field
|
||||
*
|
||||
* 00b - Associated with Logical Unit
|
||||
* 01b - Associated with target port
|
||||
* 10b - Associated with SCSI Target device
|
||||
* 11b - Reserved
|
||||
*/
|
||||
type AssociationField int
|
||||
|
||||
var (
|
||||
ASS_LU AssociationField = 0
|
||||
ASS_TGT_PORT AssociationField = 0x10
|
||||
ASS_TGT_DEV AssociationField = 0x20
|
||||
)
|
||||
|
||||
/*
|
||||
* Designator type - SPC-4 Reference
|
||||
*
|
||||
* 0 - Vendor specific - 7.6.3.3
|
||||
* 1 - T10 vendor ID - 7.6.3.4
|
||||
* 2 - EUI-64 - 7.6.3.5
|
||||
* 3 - NAA - 7.6.3.6
|
||||
* 4 - Relative Target port identifier - 7.6.3.7
|
||||
* 5 - Target Port group - 7.6.3.8
|
||||
* 6 - Logical Unit group - 7.6.3.9
|
||||
* 7 - MD5 logical unit identifier - 7.6.3.10
|
||||
* 8 - SCSI name string - 7.6.3.11
|
||||
*/
|
||||
type DesignatorType int
|
||||
|
||||
var (
|
||||
DESG_VENDOR DesignatorType = iota
|
||||
DESG_T10 DesignatorType
|
||||
DESG_EUI64 DesignatorType
|
||||
DESG_NAA DesignatorType
|
||||
DESG_REL_TGT_PORT DesignatorType
|
||||
DESG_TGT_PORT_GRP DesignatorType
|
||||
DESG_LU_GRP DesignatorType
|
||||
DESG_MD5 DesignatorType
|
||||
DESG_SCSI DesignatorType
|
||||
)
|
||||
31
pkg/scsi/target.go
Normal file
31
pkg/scsi/target.go
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
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 scsi
|
||||
|
||||
var SCSITargetState int
|
||||
|
||||
var (
|
||||
TargetOnline SCSITargetState = 1
|
||||
TargetReady SCSITargetState = 2
|
||||
)
|
||||
|
||||
type SCSITarget struct {
|
||||
Name string
|
||||
TID int
|
||||
LID int
|
||||
State SCSITargetState
|
||||
}
|
||||
50
pkg/util/util.go
Normal file
50
pkg/util/util.go
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
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 util
|
||||
|
||||
// ParseKVText parses iSCSI key value data.
|
||||
func ParseKVText(txt []byte) map[string]string {
|
||||
m := make(map[string]string)
|
||||
var kv, sep int
|
||||
var key string
|
||||
for i := 0; i < len(txt); i++ {
|
||||
if txt[i] == '=' {
|
||||
if key == "" {
|
||||
sep = i
|
||||
key = string(txt[kv:sep])
|
||||
}
|
||||
continue
|
||||
}
|
||||
if txt[i] == 0 && key != "" {
|
||||
m[key] = string(txt[sep+1 : i])
|
||||
key = ""
|
||||
kv = i + 1
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func MarshalKVText(kv map[string]string) []byte {
|
||||
var data []byte
|
||||
for k, v := range kv {
|
||||
data = append(data, []byte(k)...)
|
||||
data = append(data, '=')
|
||||
data = append(data, []byte(v)...)
|
||||
data = append(data, 0)
|
||||
}
|
||||
return data
|
||||
}
|
||||
21
pkg/version/version.go
Normal file
21
pkg/version/version.go
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
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 version
|
||||
|
||||
const (
|
||||
VERSION = "0.1"
|
||||
)
|
||||
Reference in New Issue
Block a user