Merge pull request #21 from orzhang/multi-port

iSCSI/SCSI multi port/ALUA support
This commit is contained in:
Le Zhang
2016-10-18 17:02:49 +08:00
committed by GitHub
17 changed files with 333 additions and 107 deletions

View File

@@ -26,7 +26,7 @@ script:
- go test -v ./pkg/... - go test -v ./pkg/...
- dd if=/dev/zero of=/var/tmp/disk.img bs=1024 count=10240 - dd if=/dev/zero of=/var/tmp/disk.img bs=1024 count=10240
- mkdir ${HOME}/.gotgt - mkdir ${HOME}/.gotgt
- echo '{"storages":[{"deviceID":1000,"path":"file:/var/tmp/disk.img","online":true}],"targets":{"iqn.2016-09.com.gotgt.gostor:example_tgt_0":{"portals":["127.0.0.1"],"luns":{"0":1000}}}}' > ${HOME}/.gotgt/config.json - echo '{"storages":[{"deviceID":1000,"path":"file:/var/tmp/disk.img","online":true}],"iscsiportals":[{"id":0,"portal":"127.0.0.1:3260"}],"iscsitargets":{"iqn.2016-09.com.gotgt.gostor:example_tgt_0":{"tpgts":{"1":[0]},"luns":{"0":1000}}}}' > ${HOME}/.gotgt/config.json
- ./citd -v 4 1>/dev/null 2>&1 & - ./citd -v 4 1>/dev/null 2>&1 &
# libiscsi test # libiscsi test
- mkdir ${HOME}/libiscsi - mkdir ${HOME}/libiscsi

View File

@@ -76,8 +76,8 @@ Help Options:
os.Exit(1) os.Exit(1)
} }
for tgtname, tgt := range config.Targets { for tgtname := range config.ISCSITargets {
targetDriver.NewTarget(tgtname, tgt.Portals) targetDriver.NewTarget(tgtname, config)
} }
runtime.GOMAXPROCS(runtime.NumCPU()) runtime.GOMAXPROCS(runtime.NumCPU())

View File

@@ -149,13 +149,14 @@ type SCSIDataBuffer struct {
} }
type SCSICommand struct { type SCSICommand struct {
Target *SCSITarget Target *SCSITarget
DeviceID uint64 DeviceID uint64
Device *SCSILu Device *SCSILu
State uint64 State uint64
Direction SCSIDataDirection Direction SCSIDataDirection
InSDBBuffer SCSIDataBuffer InSDBBuffer SCSIDataBuffer
OutSDBBuffer SCSIDataBuffer OutSDBBuffer SCSIDataBuffer
RelTargetPortID uint16
// Command ITN ID // Command ITN ID
CommandITNID uint64 CommandITNID uint64
Offset uint64 Offset uint64
@@ -187,16 +188,26 @@ type ITNexusLuInfo struct {
Prevent int Prevent int
} }
type SCSITarget struct { type SCSITargetPort struct {
Name string `json:"name"` RelativeTargetPortID uint16
TID int `json:"tid"` TargetPortName string
LID int `json:"lid"` }
State SCSITargetState `json:"state"`
Devices LUNMap `json:"-"`
LUN0 *SCSILu `json:"-"`
ITNexus []*ITNexus `json:"itnexus"`
SCSITargetDriver interface{} `json:"-"` type TargetPortGroup struct {
GroupID uint16
TargetPortGroup []*SCSITargetPort `json:"targetportgroup"`
}
type SCSITarget struct {
Name string `json:"name"`
TID int `json:"tid"`
LID int `json:"lid"`
State SCSITargetState `json:"state"`
Devices LUNMap `json:"-"`
LUN0 *SCSILu `json:"-"`
ITNexus []*ITNexus `json:"itnexus"`
TargetPortGroups []*TargetPortGroup `json:"tpg"`
SCSITargetDriver interface{} `json:"-"`
} }
type SCSITargetDriverState int type SCSITargetDriverState int

View File

@@ -34,13 +34,23 @@ Format of configuration file
"deviceID": integer, uniqu device id, "deviceID": integer, uniqu device id,
"path": string, <protocal>:<absolute/file/path>", "path": string, <protocal>:<absolute/file/path>",
"online": bool, online/offline "online": bool, online/offline
}, }
], ],
"portals": [
{
"id": integer, uniqu portal id
"portal":string, <IP>:<PORT>
}
],
"targets": { "targets": {
<target name >: { <target name >: {
"portals": [ "tpgts":{
<IP Addresswith Port(assumed port as 3260 without port information> <tpgt number>: [<portal id[,portal id....]]
], }
//n shoud be an value from 0 ~ 65535
"luns": { "luns": {
<lu number for the target>: <mappingd with the device ID> <lu number for the target>: <mappingd with the device ID>
} }
@@ -54,27 +64,29 @@ Example of the configuration file
"storages": [ "storages": [
{ {
"deviceID": 1000, "deviceID": 1000,
"path": "file:/tmp/image", "path": "file:/tmp/disk.img",
"online": true
},
{
"deviceID": 2000,
"path": "ceph:/rbd/image",
"online": true "online": true
} }
], ],
"targets": { "iscsiportals":[
{
"id":0,
"portal":"192.168.159.1:3260"
}
],
"iscsitargets": {
"iqn.2016-09.com.gotgt.gostor:example_tgt_0": { "iqn.2016-09.com.gotgt.gostor:example_tgt_0": {
"portals": [ "tpgts": {
"192.168.1.1" "1":[0]
], }
,
"luns": { "luns": {
"1": 1000 "1": 1000
"2": 2000
} }
} }
} }
} }
*/ */
const ( const (
@@ -93,14 +105,20 @@ type BackendStorage struct {
Online bool `json:"online"` Online bool `json:"online"`
} }
type Target struct { type ISCSIPortalInfo struct {
Portals []string `json:"portals"` ID uint16 `json:"id"`
LUNs map[string]uint64 `json:"luns"` Portal string `json:"portal"`
}
type ISCSITarget struct {
TPGTs map[string][]uint64 `json:"tpgts"`
LUNs map[string]uint64 `json:"luns"`
} }
type Config struct { type Config struct {
Storages []BackendStorage `json:"storages"` Storages []BackendStorage `json:"storages"`
Targets map[string]Target `json:"targets"` ISCSIPortals []ISCSIPortalInfo `json:"iscsiportals"`
ISCSITargets map[string]ISCSITarget `json:"iscsitargets"`
} }
func init() { func init() {
@@ -126,7 +144,7 @@ func Load(configDir string) (*Config, error) {
filename := filepath.Join(configDir, ConfigFileName) filename := filepath.Join(configDir, ConfigFileName)
config = &Config{ config = &Config{
Targets: make(map[string]Target), ISCSITargets: make(map[string]ISCSITarget),
} }
// Try happy path first - latest config file // Try happy path first - latest config file

View File

@@ -272,7 +272,8 @@ func (m *ISCSICommand) dataInBytes() []byte {
} }
buf.WriteByte(b) buf.WriteByte(b)
buf.WriteByte(0x00) // 4 buf.WriteByte(0x00) // 4
buf.Write(util.MarshalUint64(uint64(len(m.RawData)))[5:]) // 5-8 buf.Write(util.MarshalUint64(uint64(len(m.RawData)))[5:]) // 5-8
// Skip through to byte 16 // Skip through to byte 16
for i := 0; i < 8; i++ { for i := 0; i < 8; i++ {

View File

@@ -61,6 +61,7 @@ type iscsiConnection struct {
conn net.Conn conn net.Conn
initiator string initiator string
initiatorAlias string initiatorAlias string
tpgt uint16
rxBuffer []byte rxBuffer []byte
txBuffer []byte txBuffer []byte

View File

@@ -18,21 +18,24 @@ package iscsit
import ( import (
"bytes" "bytes"
"errors"
"fmt" "fmt"
"net" "net"
"os" "os"
"strconv"
"github.com/golang/glog" "github.com/golang/glog"
"github.com/gostor/gotgt/pkg/api" "github.com/gostor/gotgt/pkg/api"
"github.com/gostor/gotgt/pkg/config"
"github.com/gostor/gotgt/pkg/port" "github.com/gostor/gotgt/pkg/port"
"github.com/gostor/gotgt/pkg/scsi" "github.com/gostor/gotgt/pkg/scsi"
"github.com/gostor/gotgt/pkg/util" "github.com/gostor/gotgt/pkg/util"
) )
type ISCSITargetService struct { type ISCSITargetService struct {
SCSI *scsi.SCSITargetService SCSI *scsi.SCSITargetService
Name string Name string
Targets map[string]*ISCSITarget iSCSITargets map[string]*ISCSITarget
} }
func init() { func init() {
@@ -41,47 +44,86 @@ func init() {
func NewISCSITargetService(base *scsi.SCSITargetService) (port.SCSITargetService, error) { func NewISCSITargetService(base *scsi.SCSITargetService) (port.SCSITargetService, error) {
return &ISCSITargetService{ return &ISCSITargetService{
Name: "iscsi", Name: "iscsi",
Targets: map[string]*ISCSITarget{}, iSCSITargets: map[string]*ISCSITarget{},
SCSI: base, SCSI: base,
}, nil }, nil
} }
func (s *ISCSITargetService) NewTarget(target string, portals []string) (port.SCSITargetDriver, error) { func (s *ISCSITargetService) NewTarget(tgtName string, configInfo *config.Config) (port.SCSITargetDriver, error) {
if _, ok := s.Targets[target]; ok { if _, ok := s.iSCSITargets[tgtName]; ok {
return nil, fmt.Errorf("target name has been existed") return nil, fmt.Errorf("target name has been existed")
} }
stgt, err := s.SCSI.NewSCSITarget(len(s.Targets), "iscsi", target) stgt, err := s.SCSI.NewSCSITarget(len(s.iSCSITargets), "iscsi", tgtName)
if err != nil { if err != nil {
return nil, err return nil, err
} }
tgt := newISCSITarget(stgt) tgt := newISCSITarget(stgt)
s.Targets[target] = tgt s.iSCSITargets[tgtName] = tgt
for _, portal := range portals { scsiTPG := tgt.SCSITarget.TargetPortGroups[0]
s.AddNewPortal(target, portal) targetConfig := configInfo.ISCSITargets[tgtName]
for tpgt, portalIDArrary := range targetConfig.TPGTs {
tpgtNumber, _ := strconv.ParseUint(tpgt, 10, 16)
tgt.TPGTs[uint16(tpgtNumber)] = &iSCSITPGT{uint16(tpgtNumber), make(map[string]struct{})}
targetPortName := fmt.Sprintf("%s,t,0x%02x", tgtName, tpgtNumber)
scsiTPG.TargetPortGroup = append(scsiTPG.TargetPortGroup, &api.SCSITargetPort{uint16(tpgtNumber), targetPortName})
for _, portalID := range portalIDArrary {
portal := configInfo.ISCSIPortals[portalID]
s.AddiSCSIPortal(tgtName, uint16(tpgtNumber), portal.Portal)
}
} }
return tgt, nil return tgt, nil
} }
func (s *ISCSITargetService) AddNewPortal(tgtName string, portal string) error { func (s *ISCSITargetService) AddiSCSIPortal(tgtName string, tpgt uint16, portal string) error {
target := s.Targets[tgtName] var (
tgtPortals := target.Portals ok bool
_, ok := tgtPortals[portal] errMsg string
if !ok { target *ISCSITarget
tgtPortals[portal] = struct{}{} tpgtInfo *iSCSITPGT
)
if target, ok = s.iSCSITargets[tgtName]; !ok {
errMsg = fmt.Sprintf("no target %s", tgtName)
return errors.New(errMsg)
} }
if tpgtInfo, ok = target.TPGTs[tpgt]; !ok {
errMsg = fmt.Sprintf("no tpgt %d", tpgt)
return errors.New(errMsg)
}
tgtPortals := tpgtInfo.Portals
if _, ok = tgtPortals[portal]; !ok {
tgtPortals[portal] = struct{}{}
} else {
errMsg := fmt.Sprintf("duplicate portal %s,in %s,%d", portal, tgtName, tpgt)
return errors.New(errMsg)
}
return nil return nil
} }
func (s *ISCSITargetService) HasPortal(tgtName string, portal string) bool { func (s *ISCSITargetService) HasPortal(tgtName string, tpgt uint16, portal string) bool {
target := s.Targets[tgtName] var (
tgtPortals := target.Portals ok bool
target *ISCSITarget
tpgtInfo *iSCSITPGT
)
if len(tgtPortals) == 0 { if target, ok = s.iSCSITargets[tgtName]; !ok {
return false
}
if tpgtInfo, ok = target.TPGTs[tpgt]; !ok {
return false
}
tgtPortals := tpgtInfo.Portals
if _, ok = tgtPortals[portal]; !ok {
return false
} else {
return true return true
} }
_, ok := tgtPortals[portal]
return ok
} }
func (s *ISCSITargetService) Run() error { func (s *ISCSITargetService) Run() error {
@@ -254,6 +296,8 @@ func (s *ISCSITargetService) iscsiExecLogin(conn *iscsiConnection) error {
var ( var (
target *ISCSITarget target *ISCSITarget
cmd = conn.req cmd = conn.req
TPGT uint16
err error
) )
conn.resp = &ISCSICommand{ conn.resp = &ISCSICommand{
OpCode: OpLoginResp, OpCode: OpLoginResp,
@@ -298,7 +342,7 @@ func (s *ISCSITargetService) iscsiExecLogin(conn *iscsiConnection) error {
if conn.sessionType == SESSION_DISCOVERY { if conn.sessionType == SESSION_DISCOVERY {
conn.tid = 0xffff conn.tid = 0xffff
} else { } else {
for _, t := range s.Targets { for _, t := range s.iSCSITargets {
if t.SCSITarget.Name == targetName { if t.SCSITarget.Name == targetName {
target = t target = t
break break
@@ -308,7 +352,15 @@ func (s *ISCSITargetService) iscsiExecLogin(conn *iscsiConnection) error {
conn.state = CONN_STATE_EXIT conn.state = CONN_STATE_EXIT
return fmt.Errorf("No target found with name(%s)", targetName) return fmt.Errorf("No target found with name(%s)", targetName)
} }
TPGT, err = target.FindTPG(conn.conn.LocalAddr().String())
if err != nil {
conn.state = CONN_STATE_EXIT
return err
}
conn.tpgt = TPGT
conn.tid = target.TID conn.tid = target.TID
} }
switch conn.state { switch conn.state {
case CONN_STATE_FREE: case CONN_STATE_FREE:
@@ -361,13 +413,16 @@ func (s *ISCSITargetService) iscsiExecText(conn *iscsiConnection) error {
keys := util.ParseKVText(cmd.RawData) keys := util.ParseKVText(cmd.RawData)
if st, ok := keys["SendTargets"]; ok { if st, ok := keys["SendTargets"]; ok {
if st == "All" { if st == "All" {
for name, tgt := range s.Targets { for name, tgt := range s.iSCSITargets {
glog.V(2).Infof("iscsi target: %v", name) glog.V(2).Infof("iscsi target: %v", name)
glog.V(2).Infof("iscsi target portals: %v", tgt.Portals) //glog.V(2).Infof("iscsi target portals: %v", tgt.Portals)
result = append(result, util.KeyValue{"TargetName", name}) result = append(result, util.KeyValue{"TargetName", name})
for portal := range tgt.Portals { for _, tpgt := range tgt.TPGTs {
result = append(result, util.KeyValue{"TargetAddress", portal + ",1"}) for portal := range tpgt.Portals {
targetPort := fmt.Sprintf("%s,%d", portal, tpgt.TPGT)
result = append(result, util.KeyValue{"TargetAddress", targetPort})
}
} }
} }
} }
@@ -754,6 +809,7 @@ func (s *ISCSITargetService) iscsiExecTask(task *iscsiTask) error {
task.scmd.SCBLength = len(cmd.CDB) task.scmd.SCBLength = len(cmd.CDB)
task.scmd.Lun = cmd.LUN task.scmd.Lun = cmd.LUN
task.scmd.Tag = uint64(cmd.TaskTag) task.scmd.Tag = uint64(cmd.TaskTag)
task.scmd.RelTargetPortID = task.conn.tpgt
task.state = taskSCSI task.state = taskSCSI
if task.scmd.OutSDBBuffer.Buffer == nil { if task.scmd.OutSDBBuffer.Buffer == nil {
task.scmd.OutSDBBuffer.Buffer = bytes.NewBuffer(cmd.RawData) task.scmd.OutSDBBuffer.Buffer = bytes.NewBuffer(cmd.RawData)

View File

@@ -17,7 +17,13 @@ limitations under the License.
// iSCSI Target Driver // iSCSI Target Driver
package iscsit package iscsit
import "github.com/gostor/gotgt/pkg/api" import (
"errors"
"fmt"
"strings"
"github.com/gostor/gotgt/pkg/api"
)
const ( const (
IOSTATE_FREE = iota IOSTATE_FREE = iota
@@ -64,10 +70,15 @@ type ISCSIRedirectInfo struct {
Callback string Callback string
} }
type iSCSITPGT struct {
TPGT uint16 /* Mapping to SCSI Reltive Target Port ID */
Portals map[string]struct{}
}
type ISCSITarget struct { type ISCSITarget struct {
api.SCSITarget api.SCSITarget
api.SCSITargetDriverCommon api.SCSITargetDriverCommon
Portals map[string]struct{} TPGTs map[uint16]*iSCSITPGT
Sessions []*ISCSISession Sessions []*ISCSISession
SessionParam []ISCSISessionParam SessionParam []ISCSISessionParam
Alias string Alias string
@@ -78,10 +89,22 @@ type ISCSITarget struct {
NopCount int NopCount int
} }
func (tgt *ISCSITarget) FindTPG(portal string) (uint16, error) {
for tpgt, TPG := range tgt.TPGTs {
for tgtPortal := range TPG.Portals {
if strings.EqualFold(portal, tgtPortal) {
return tpgt, nil
}
}
}
errMsg := fmt.Sprintf("No TPGT found with IP(%s)", portal)
return 0, errors.New(errMsg)
}
func newISCSITarget(target *api.SCSITarget) *ISCSITarget { func newISCSITarget(target *api.SCSITarget) *ISCSITarget {
return &ISCSITarget{ return &ISCSITarget{
SCSITarget: *target, SCSITarget: *target,
Portals: make(map[string]struct{}), TPGTs: make(map[uint16]*iSCSITPGT),
} }
} }

View File

@@ -221,7 +221,7 @@ func (s *ISCSITargetService) NewISCSISession(conn *iscsiConnection) (*ISCSISessi
tsih uint64 tsih uint64
) )
for _, t := range s.Targets { for _, t := range s.iSCSITargets {
if t.TID == conn.tid { if t.TID == conn.tid {
target = t target = t
break break

View File

@@ -19,13 +19,13 @@ package port
import ( import (
"fmt" "fmt"
"github.com/gostor/gotgt/pkg/config"
"github.com/gostor/gotgt/pkg/scsi" "github.com/gostor/gotgt/pkg/scsi"
) )
type SCSITargetService interface { type SCSITargetService interface {
Run() error Run() error
NewTarget(string, []string) (SCSITargetDriver, error) NewTarget(string, *config.Config) (SCSITargetDriver, error)
AddNewPortal(string, string) error
} }
type TargetServiceFunc func(*scsi.SCSITargetService) (SCSITargetService, error) type TargetServiceFunc func(*scsi.SCSITargetService) (SCSITargetService, error)

View File

@@ -16,6 +16,10 @@ limitations under the License.
package scsi package scsi
import (
"github.com/gostor/gotgt/pkg/util"
)
type SCSIPRServiceAction byte type SCSIPRServiceAction byte
type SCSIPRType byte type SCSIPRType byte
@@ -73,3 +77,39 @@ const (
func SCSICDBGroupID(opcode byte) byte { func SCSICDBGroupID(opcode byte) byte {
return ((opcode >> 5) & 0x7) return ((opcode >> 5) & 0x7)
} }
/*
* Transfer Length (if any)
* Parameter List Length (if any)
* Allocation Length (if any)
*/
func SCSICDBBufXLength(scb []byte) (int64, bool) {
var (
opcode byte
length int64
group byte
ok bool = true
)
opcode = scb[0]
group = SCSICDBGroupID(opcode)
switch group {
case CBD_GROUPID_0:
length = int64(scb[4])
case CBD_GROUPID_1, CBD_GROUPID_2:
length = int64(util.GetUnalignedUint16(scb[7:9]))
case CBD_GROUPID_3:
if opcode == 0x7F {
length = int64(scb[7])
} else {
ok = false
}
case CBD_GROUPID_4:
length = int64(util.GetUnalignedUint32(scb[6:10]))
case CBD_GROUPID_5:
length = int64(util.GetUnalignedUint32(scb[10:14]))
default:
ok = false
}
return length, ok
}

View File

@@ -158,8 +158,8 @@ func NewSBCDevice(deviceType api.SCSIDeviceType) api.SCSIDeviceProtocol {
sbc.SCSIDeviceOps[api.MODE_SELECT_10] = NewSCSIDeviceOperation(SBCModeSelect, nil, PR_WE_FA|PR_EA_FA|PR_EA_FN|PR_WE_FN) sbc.SCSIDeviceOps[api.MODE_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.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_IN] = NewSCSIDeviceOperation(SPCIllegalOp, nil, 0)
sbc.SCSIDeviceOps[api.PERSISTENT_RESERVE_OUT] = NewSCSIDeviceOperation(SPCServiceAction, nil, 0) sbc.SCSIDeviceOps[api.PERSISTENT_RESERVE_OUT] = NewSCSIDeviceOperation(SPCIllegalOp, nil, 0)
sbc.SCSIDeviceOps[api.READ_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN) sbc.SCSIDeviceOps[api.READ_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN)
sbc.SCSIDeviceOps[api.WRITE_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN|PR_WE_FA|PR_WE_FN) sbc.SCSIDeviceOps[api.WRITE_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN|PR_WE_FA|PR_WE_FN)

View File

@@ -124,6 +124,7 @@ func NewSCSIDeviceOperation(fn api.CommandFunc, sa *SCSIServiceAction, pr uint8)
func BuildSenseData(cmd *api.SCSICommand, key byte, asc SCSISubError) { func BuildSenseData(cmd *api.SCSICommand, key byte, asc SCSISubError) {
senseBuffer := &bytes.Buffer{} senseBuffer := &bytes.Buffer{}
inBufLen, ok := SCSICDBBufXLength(cmd.SCB.Bytes())
if cmd.Device.Attrs.SenseFormat { if cmd.Device.Attrs.SenseFormat {
// descriptor format // descriptor format
@@ -149,8 +150,19 @@ func BuildSenseData(cmd *api.SCSICommand, key byte, asc SCSISubError) {
} }
senseBuffer.WriteByte((byte(asc) >> 8) & 0xff) senseBuffer.WriteByte((byte(asc) >> 8) & 0xff)
senseBuffer.WriteByte(byte(asc) & 0xff) senseBuffer.WriteByte(byte(asc) & 0xff)
senseBuffer.WriteByte(0x00)
senseBuffer.WriteByte(0x00)
senseBuffer.WriteByte(0x00)
senseBuffer.WriteByte(0x00)
cmd.SenseLength = length + 8 cmd.SenseLength = length + 8
} }
if ok {
if int64(len(senseBuffer.Bytes())) > inBufLen {
senseBuffer.Truncate(int(inBufLen))
}
} else {
glog.V(2).Infof("cannot calc cbd alloc length. truncate failed")
}
cmd.Result = key cmd.Result = key
cmd.SenseBuffer = senseBuffer cmd.SenseBuffer = senseBuffer
} }

View File

@@ -76,7 +76,7 @@ func InitSCSILUMap(config *config.Config) error {
globalSCSILUMap.AllDevices[bs.DeviceID] = lu globalSCSILUMap.AllDevices[bs.DeviceID] = lu
} }
for tgtName, tgt := range config.Targets { for tgtName, tgt := range config.ISCSITargets {
for lunstr, deviceID := range tgt.LUNs { for lunstr, deviceID := range tgt.LUNs {
lun, err := strconv.ParseUint(lunstr, 10, 64) lun, err := strconv.ParseUint(lunstr, 10, 64)
if err != nil { if err != nil {

View File

@@ -122,8 +122,8 @@ const (
INQUIRY_SCCS = byte(0x80) INQUIRY_SCCS = byte(0x80)
INQUIRY_AAC = byte(0x40) INQUIRY_AAC = byte(0x40)
INQUIRY_TPGS_NO = byte(0x00) INQUIRY_TPGS_NO = byte(0x00)
INQUIRY_TPGS_IMPLICIT = byte(0x20) INQUIRY_TPGS_IMPLICIT = byte(0x10)
INQUIRY_TPGS_EXPLICIT = byte(0x10) INQUIRY_TPGS_EXPLICIT = byte(0x20)
INQUIRY_TPGS_BOTH = byte(0x30) INQUIRY_TPGS_BOTH = byte(0x30)
INQUIRY_3PC = byte(0x08) INQUIRY_3PC = byte(0x08)
INQUIRY_Reserved = byte(0x06) INQUIRY_Reserved = byte(0x06)
@@ -189,11 +189,12 @@ const (
const ( const (
SCSI_VendorID = "GOSTOR" SCSI_VendorID = "GOSTOR"
SCSI_ProductID = "GOTGT-VDISK" SCSI_ProductID = "GOTGT"
) )
func SPCIllegalOp(host int, cmd *api.SCSICommand) api.SAMStat { func SPCIllegalOp(host int, cmd *api.SCSICommand) api.SAMStat {
return api.SAMStatGood BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
return api.SAMStatCheckCondition
} }
func SPCLuOffline(lu *api.SCSILu) error { func SPCLuOffline(lu *api.SCSILu) error {
@@ -282,12 +283,16 @@ func InquiryPage0x83(host int, cmd *api.SCSICommand) (*bytes.Buffer, uint16) {
buf = &bytes.Buffer{} buf = &bytes.Buffer{}
descBuf = &bytes.Buffer{} descBuf = &bytes.Buffer{}
data []byte = []byte{} data []byte = []byte{}
pageLength uint16 = 0 portName []byte
pageLength uint16 = 0
portID uint16 = cmd.RelTargetPortID
portGroup uint16 = FindTargetGroup(cmd.Target, portID)
targetPort *api.SCSITargetPort = FindTargetPort(cmd.Target, portID)
) )
//DESCRIPTOR 1 TARGET NAME //DESCRIPTOR 1 TARGET NAME
descBuf.WriteByte((PIV_ISCSI << 4) | INQ_CODE_ASCII) descBuf.WriteByte((PIV_ISCSI << 4) | INQ_CODE_ASCII)
descBuf.WriteByte(0x80 | ASS_TGT_PORT | DESG_VENDOR) descBuf.WriteByte(0x80 | (ASS_TGT_PORT << 4) | DESG_VENDOR)
descBuf.WriteByte(0x00) descBuf.WriteByte(0x00)
//length //length
descBuf.WriteByte(byte(len([]byte(cmd.Target.Name)))) descBuf.WriteByte(byte(len([]byte(cmd.Target.Name))))
@@ -296,7 +301,7 @@ func InquiryPage0x83(host int, cmd *api.SCSICommand) (*bytes.Buffer, uint16) {
//DESCRIPTOR 2 NNA Locally //DESCRIPTOR 2 NNA Locally
descBuf.WriteByte((PIV_ISCSI << 4) | INQ_CODE_BIN) descBuf.WriteByte((PIV_ISCSI << 4) | INQ_CODE_BIN)
descBuf.WriteByte(0x80 | ASS_TGT_PORT | DESG_NAA) descBuf.WriteByte(0x80 | (ASS_LU << 4) | DESG_NAA)
descBuf.WriteByte(0x00) descBuf.WriteByte(0x00)
//length //length
descBuf.WriteByte(0x08) descBuf.WriteByte(0x08)
@@ -305,25 +310,37 @@ func InquiryPage0x83(host int, cmd *api.SCSICommand) (*bytes.Buffer, uint16) {
//TODO: Target Port Group(0x05), Relative Target port identifier(0x04) //TODO: Target Port Group(0x05), Relative Target port identifier(0x04)
/* //DESCRIPTOR 3 TPG
//DESCRIPTOR 3 TPG descBuf.WriteByte((PIV_ISCSI << 4) | INQ_CODE_BIN)
descBuf.WriteByte((PIV_ISCSI << 4) | INQ_CODE_BIN) descBuf.WriteByte(0x80 | (ASS_TGT_PORT << 4) | DESG_TGT_PORT_GRP)
descBuf.WriteByte(0x80 | ASS_TGT_PORT | DESG_REL_TGT_PORT) descBuf.WriteByte(0x00)
descBuf.WriteByte(0x00) //length
//length descBuf.WriteByte(0x04)
descBuf.WriteByte(0x08) //TPG
//TPG descBuf.WriteByte(0x00)
binary.Write(descBuf, binary.BigEndian,) descBuf.WriteByte(0x00)
binary.Write(descBuf, binary.BigEndian, portGroup)
//DESCRIPTOR 4 RTPI //DESCRIPTOR 4 Relative Target Port ID
descBuf.WriteByte((PIV_ISCSI << 4) | INQ_CODE_BIN) descBuf.WriteByte((PIV_ISCSI << 4) | INQ_CODE_BIN)
descBuf.WriteByte(0x80 | ASS_TGT_PORT | DESG_NAA) descBuf.WriteByte(0x80 | (ASS_TGT_PORT << 4) | DESG_REL_TGT_PORT)
descBuf.WriteByte(0x00) descBuf.WriteByte(0x00)
//length //length
descBuf.WriteByte(0x08) descBuf.WriteByte(0x04)
//RTPGI //RTPGI
binary.Write(descBuf, binary.BigEndian,) descBuf.WriteByte(0x00)
*/ descBuf.WriteByte(0x00)
binary.Write(descBuf, binary.BigEndian, portID)
//DESCRIPTOR 5 SCSI Name,Port
portName = util.StringToByte(targetPort.TargetPortName, 4, 256)
descBuf.WriteByte((PIV_ISCSI << 4) | INQ_CODE_UTF8)
descBuf.WriteByte(0x80 | (ASS_TGT_PORT << 4) | DESG_SCSI)
descBuf.WriteByte(0x00)
//length
descBuf.WriteByte(byte(len(portName)))
//RTPGI
descBuf.Write(portName)
data = descBuf.Bytes() data = descBuf.Bytes()
pageLength = uint16(len(data)) pageLength = uint16(len(data))
@@ -395,7 +412,7 @@ func SPCInquiry(host int, cmd *api.SCSICommand) api.SAMStat {
} else { } else {
//byte 5 //byte 5
//SCCS(0) AAC(0) TPGS(0) 3PC(0) PROTECT(0) //SCCS(0) AAC(0) TPGS(0) 3PC(0) PROTECT(0)
addBuf.WriteByte(0x00) addBuf.WriteByte(INQUIRY_TPGS_IMPLICIT)
//byte 6 //byte 6
//ENCSERV(0) VS(0) MULTIP(0) ADDR16(0) //ENCSERV(0) VS(0) MULTIP(0) ADDR16(0)
addBuf.WriteByte(0x00) addBuf.WriteByte(0x00)

View File

@@ -31,15 +31,40 @@ func (s *SCSITargetService) NewSCSITarget(tid int, driverName, name string) (*ap
// verify the low level driver // verify the low level driver
var target = &api.SCSITarget{ var target = &api.SCSITarget{
Name: name, Name: name,
TID: tid, TID: tid,
TargetPortGroups: []*api.TargetPortGroup{},
} }
tpg := &api.TargetPortGroup{0, []*api.SCSITargetPort{}}
s.Targets = append(s.Targets, target) s.Targets = append(s.Targets, target)
target.Devices = GetTargetLUNMap(target.Name) target.Devices = GetTargetLUNMap(target.Name)
target.LUN0 = NewLUN0() target.LUN0 = NewLUN0()
target.TargetPortGroups = append(target.TargetPortGroups, tpg)
return target, nil return target, nil
} }
func FindTargetGroup(target *api.SCSITarget, relPortID uint16) uint16 {
for _, tpg := range target.TargetPortGroups {
for _, port := range tpg.TargetPortGroup {
if port.RelativeTargetPortID == relPortID {
return tpg.GroupID
}
}
}
return 0
}
func FindTargetPort(target *api.SCSITarget, relPortID uint16) *api.SCSITargetPort {
for _, tpg := range target.TargetPortGroups {
for _, port := range tpg.TargetPortGroup {
if port.RelativeTargetPortID == relPortID {
return port
}
}
}
return nil
}
func deviceReserve(cmd *api.SCSICommand) error { func deviceReserve(cmd *api.SCSICommand) error {
var lu *api.SCSILu var lu *api.SCSILu
lun := *(*uint64)(unsafe.Pointer(&cmd.Lun)) lun := *(*uint64)(unsafe.Pointer(&cmd.Lun))

View File

@@ -90,6 +90,28 @@ func MarshalUint64(i uint64) []byte {
return data return data
} }
func StringToByte(str string, align int, maxlength int) []byte {
var (
data []byte
data2 []byte
length int
d int
)
data = []byte(str)
length = len(data)
d = align - (length % align)
if (length + d) > maxlength {
data = ([]byte(str))[0:maxlength]
return data
} else {
data2 = make([]byte, length+d)
copy(data2, data)
return data2
}
}
const ( const (
POSIX_FADV_NORMAL = iota POSIX_FADV_NORMAL = iota
POSIX_FADV_RANDOM POSIX_FADV_RANDOM