mapping lun and fix portal management

This commit is contained in:
Le Zhang
2016-10-04 13:39:55 +08:00
parent 89382bddb0
commit c9b93c7527
16 changed files with 298 additions and 119 deletions

View File

@@ -1,10 +1,11 @@
sudo: required
dist: trusty
env:
- TARGET=iqn.2016-09.com.gotgt.gostor:example_tgt_0
language: go
go:
- 1.4
- 1.5
- 1.6
install:
- true
@@ -23,7 +24,7 @@ script:
- hack/verify-gofmt.sh
- dd if=/dev/zero of=/var/tmp/disk.img bs=1024 count=10240
- mkdir ${HOME}/.gotgt
- echo '{"targets":{"test-iscsi-target":{"name":"test-iscsi-target","luns":["/var/tmp/disk.img"]}}}' > ${HOME}/.gotgt/config.json
- 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
- ./citd -v 4 1>/dev/null 2>&1 &
# libiscsi test
- mkdir ${HOME}/libiscsi
@@ -33,11 +34,11 @@ script:
- ./autogen.sh
- ./configure
- make
- ./test-tool/iscsi-test-cu -d --test=SCSI.Read10.Simple iscsi://127.0.0.1:3260/test-iscsi-target/0
- ./test-tool/iscsi-test-cu -d --test=SCSI.Write10.Simple iscsi://127.0.0.1:3260/test-iscsi-target/0
- ./utils/iscsi-ls -s iscsi://127.0.0.1:3260/test-iscsi-target
- ./utils/iscsi-inq iscsi://127.0.0.1:3260/test-iscsi-target/0
- ./utils/iscsi-readcapacity16 iscsi://127.0.0.1:3260/test-iscsi-target/0
- ./test-tool/iscsi-test-cu -d --test=SCSI.Read10.Simple iscsi://127.0.0.1:3260/${TARGET}/0
- ./test-tool/iscsi-test-cu -d --test=SCSI.Write10.Simple iscsi://127.0.0.1:3260/${TARGET}/0
- ./utils/iscsi-ls -s iscsi://127.0.0.1:3260/${TARGET}
- ./utils/iscsi-inq iscsi://127.0.0.1:3260/${TARGET}/0
- ./utils/iscsi-readcapacity16 iscsi://127.0.0.1:3260/${TARGET}/0
# iscsi initiator test
- sudo iscsiadm -m discovery -t sendtargets -p 127.0.0.1
- sudo iscsiadm -m node -L all

16
citd.go
View File

@@ -64,18 +64,26 @@ Help Options:
os.Exit(1)
}
scsi := scsi.NewSCSITargetService()
t, err := port.NewTargetService(*flDriver, scsi)
err = scsi.InitSCSILUMap(config)
if err != nil {
glog.Error(err)
os.Exit(1)
}
service := scsi.NewSCSITargetService()
t, err := port.NewTargetService(*flDriver, service)
if err != nil {
glog.Error(err)
os.Exit(1)
}
iscsit := reflect.ValueOf(t)
// create a new target
for _, tgt := range config.Targets {
for tgtname, tgt := range config.Targets {
create := iscsit.MethodByName("NewTarget")
create.Call([]reflect.Value{reflect.ValueOf(tgt.Name), reflect.ValueOf(tgt.LUNs)})
create.Call([]reflect.Value{reflect.ValueOf(tgtname),
reflect.ValueOf(tgt.Portals)})
}
runtime.GOMAXPROCS(runtime.NumCPU())
// run a service
run := iscsit.MethodByName("Run")

View File

@@ -18,7 +18,6 @@ package api
import (
"bytes"
"errors"
"os"
)
type SCSICommandType byte
@@ -193,7 +192,7 @@ type SCSITarget struct {
TID int `json:"tid"`
LID int `json:"lid"`
State SCSITargetState `json:"state"`
Devices []*SCSILu `json:"-"`
Devices LUNMap `json:"-"`
ITNexus []*ITNexus `json:"itnexus"`
SCSITargetDriver interface{} `json:"-"`
@@ -314,10 +313,11 @@ var (
type CommandFunc func(host int, cmd *SCSICommand) SAMStat
type BackingStore interface {
Open(dev *SCSILu, path string) (*os.File, error)
Open(dev *SCSILu, path string) error
Close(dev *SCSILu) error
Init(dev *SCSILu, Opts string) error
Exit(dev *SCSILu) error
Size(dev *SCSILu) uint64
CommandSubmit(cmd *SCSICommand) error
}
@@ -336,21 +336,20 @@ type ModePage struct {
}
type SCSILu struct {
File *os.File
Address uint64
Size uint64
Lun uint64
Path string
BsoFlags int
BlockShift uint
ReserveID uint64
Attrs SCSILuPhyAttribute
ModePages []ModePage
Target *SCSITarget
Address uint64
Size uint64
Lun uint64
Path string
BsoFlags int
BlockShift uint
ReserveID uint64
Attrs SCSILuPhyAttribute
ModePages []ModePage
Storage BackingStore
DeviceProtocol SCSIDeviceProtocol
PerformCommand CommandFunc
FinishCommand func(*SCSITarget, *SCSICommand)
}
type LUNMap map[uint64]*SCSILu

View File

@@ -25,6 +25,58 @@ import (
"github.com/gostor/gotgt/pkg/homedir"
)
/*
Format of configuration file
{
"storages": [
{
"deviceID": integer, uniqu device id,
"path": string, <protocal>:<absolute/file/path>",
"online": bool, online/offline
},
],
"targets": {
<target name >: {
"portals": [
<IP Addresswith Port(assumed port as 3260 without port information>
],
"luns": {
<lu number for the target>: <mappingd with the device ID>
}
}
}
}
Example of the configuration file
{
"storages": [
{
"deviceID": 1000,
"path": "file:/tmp/image",
"online": true
},
{
"deviceID": 2000,
"path": "ceph:/rbd/image",
"online": true
}
],
"targets": {
"iqn.2016-09.com.gotgt.gostor:example_tgt_0": {
"portals": [
"192.168.1.1"
],
"luns": {
"1": 1000
"2": 2000
}
}
}
}
*/
const (
// ConfigFileName is the name of config file
ConfigFileName = "config.json"
@@ -32,17 +84,23 @@ const (
var (
configDir = os.Getenv("GOSTOR_CONFIG")
config *Config
)
type BackendStorage struct {
DeviceID uint64 `json:"deviceID"`
Path string `json:"path"`
Online bool `json:"online"`
}
type Target struct {
Name string `json:"name"`
Portals []string `json:"portals"`
LUNs []string `json:"luns"`
Portals []string `json:"portals"`
LUNs map[string]uint64 `json:"luns"`
}
type Config struct {
Storage string `json:"storage"`
Targets map[string]Target `json:"targets"`
Storages []BackendStorage `json:"storages"`
Targets map[string]Target `json:"targets"`
}
func init() {
@@ -54,6 +112,10 @@ func init() {
// ConfigDir returns the directory the configuration file is stored in
func ConfigDir() string {
return configDir
}
func GetConfig() *Config {
return config
}
// Load reads the configuration files in the given directory and return values.
@@ -63,8 +125,7 @@ func Load(configDir string) (*Config, error) {
}
filename := filepath.Join(configDir, ConfigFileName)
config := &Config{
Storage: "file",
config = &Config{
Targets: make(map[string]Target),
}

View File

@@ -22,7 +22,6 @@ import (
"net"
"os"
"runtime/debug"
"strings"
"github.com/golang/glog"
"github.com/gostor/gotgt/pkg/api"
@@ -35,7 +34,6 @@ type ISCSITargetService struct {
SCSI *scsi.SCSITargetService
Name string
Targets map[string]*ISCSITarget
Portals map[string]struct{}
}
func init() {
@@ -46,40 +44,44 @@ func NewISCSITargetService(base *scsi.SCSITargetService) (port.SCSITargetService
return &ISCSITargetService{
Name: "iscsi",
Targets: map[string]*ISCSITarget{},
Portals: map[string]struct{}{},
SCSI: base,
}, nil
}
func (s *ISCSITargetService) NewTarget(target string, luns []string) (port.SCSITargetDriver, error) {
func (s *ISCSITargetService) NewTarget(target string, portals []string) (port.SCSITargetDriver, error) {
if _, ok := s.Targets[target]; ok {
return nil, fmt.Errorf("target name has been existed")
}
stgt, err := s.SCSI.NewSCSITarget(len(s.Targets), "iscsi", target, luns)
stgt, err := s.SCSI.NewSCSITarget(len(s.Targets), "iscsi", target)
if err != nil {
return nil, err
}
tgt := newISCSITarget(stgt)
s.Targets[target] = tgt
for _, portal := range portals {
s.AddNewPortal(target, portal)
}
return tgt, nil
}
func (s *ISCSITargetService) AddNewPortal(portals []string) error {
for _, p := range portals {
if !strings.Contains(p, ":") {
p = p + ":3260"
}
s.Portals[p] = struct{}{}
func (s *ISCSITargetService) AddNewPortal(tgtName string, portal string) error {
target := s.Targets[tgtName]
tgtPortals := target.Portals
_, ok := tgtPortals[portal]
if !ok {
tgtPortals[portal] = struct{}{}
}
return nil
}
func (s *ISCSITargetService) HasPortal(portal string) bool {
if len(s.Portals) == 0 {
func (s *ISCSITargetService) HasPortal(tgtName string, portal string) bool {
target := s.Targets[tgtName]
tgtPortals := target.Portals
if len(tgtPortals) == 0 {
return true
}
_, ok := s.Portals[portal]
_, ok := tgtPortals[portal]
return ok
}
@@ -98,10 +100,7 @@ func (s *ISCSITargetService) Run() error {
glog.Error(err)
continue
}
if !s.HasPortal(conn.LocalAddr().String()) {
glog.Errorf("unexpected portal")
continue
}
glog.Info(conn.LocalAddr().String())
glog.Info("Accepting ...")
iscsiConn := &iscsiConnection{conn: conn}
iscsiConn.init()
@@ -363,14 +362,18 @@ func (s *ISCSITargetService) iscsiExecText(conn *iscsiConnection) error {
keys := util.ParseKVText(cmd.RawData)
if st, ok := keys["SendTargets"]; ok {
if st == "All" {
list, err := s.SCSI.GetTargetList()
if err != nil {
return err
for name, tgt := range s.Targets {
glog.V(2).Infof("iscsi target:", name)
glog.V(2).Infof("iscsi target portals:", tgt.Portals)
}
for _, t := range list {
result = append(result, util.KeyValue{"TargetName", t.Name})
//result = append(result, util.KeyValue{"TargetAddress", "172.16.69.1:3260,1"})
result = append(result, util.KeyValue{"TargetAddress", "127.0.0.1:3260,1"})
for name, tgt := range s.Targets {
result = append(result, util.KeyValue{"TargetName", name})
for portal := range tgt.Portals {
result = append(result, util.KeyValue{"TargetAddress", portal + ",1"})
}
}
}
}

View File

@@ -67,7 +67,7 @@ type ISCSIRedirectInfo struct {
type ISCSITarget struct {
api.SCSITarget
api.SCSITargetDriverCommon
Portals map[string]struct{}
Sessions []*ISCSISession
SessionParam []ISCSISessionParam
Alias string
@@ -81,6 +81,7 @@ type ISCSITarget struct {
func newISCSITarget(target *api.SCSITarget) *ISCSITarget {
return &ISCSITarget{
SCSITarget: *target,
Portals: make(map[string]struct{}),
}
}

View File

@@ -25,7 +25,7 @@ import (
type SCSITargetService interface {
Run() error
NewTarget(string, []string) (SCSITargetDriver, error)
AddNewPortal([]string) error
AddNewPortal(string, string) error
}
type TargetServiceFunc func(*scsi.SCSITargetService) (SCSITargetService, error)

View File

@@ -18,14 +18,13 @@ package scsi
import (
"fmt"
"os"
"github.com/gostor/gotgt/pkg/api"
)
type BaseBackingStore struct {
Name string
DataSize int
DataSize uint64
OflagsSupported int
}
@@ -52,8 +51,8 @@ type fakeBackingStore struct {
BaseBackingStore
}
func (fake *fakeBackingStore) Open(dev *api.SCSILu, path string) (*os.File, error) {
return nil, nil
func (fake *fakeBackingStore) Open(dev *api.SCSILu, path string) error {
return nil
}
func (fake *fakeBackingStore) Close(dev *api.SCSILu) error {

View File

@@ -34,6 +34,7 @@ func init() {
type FileBackingStore struct {
scsi.BaseBackingStore
File *os.File
}
func new() (api.BackingStore, error) {
@@ -46,16 +47,22 @@ func new() (api.BackingStore, error) {
}, nil
}
func (bs *FileBackingStore) Open(dev *api.SCSILu, path string) (*os.File, error) {
f, err := os.OpenFile(path, os.O_RDWR, os.ModePerm)
if err != nil {
return nil, err
func (bs *FileBackingStore) Open(dev *api.SCSILu, path string) error {
if finfo, err := os.Stat(path); err != nil {
return err
} else {
bs.DataSize = uint64(finfo.Size())
}
return f, nil
f, err := os.OpenFile(path, os.O_RDWR, os.ModePerm)
bs.File = f
return err
}
func (bs *FileBackingStore) Close(dev *api.SCSILu) error {
return dev.File.Close()
return bs.File.Close()
}
func (bs *FileBackingStore) Init(dev *api.SCSILu, Opts string) error {
@@ -66,6 +73,9 @@ func (bs *FileBackingStore) Exit(dev *api.SCSILu) error {
return nil
}
func (bs *FileBackingStore) Size(dev *api.SCSILu) uint64 {
return bs.DataSize
}
func (bs *FileBackingStore) CommandSubmit(cmd *api.SCSICommand) (err error) {
var (
scb = cmd.SCB.Bytes()
@@ -83,7 +93,7 @@ func (bs *FileBackingStore) CommandSubmit(cmd *api.SCSICommand) (err error) {
switch opcode {
case api.ORWRITE_16:
tmpbuf := []byte{}
length, err = lu.File.ReadAt(tmpbuf, int64(offset))
length, err = bs.File.ReadAt(tmpbuf, int64(offset))
if length != len(tmpbuf) {
key = scsi.MEDIUM_ERROR
asc = scsi.ASC_READ_ERROR
@@ -99,7 +109,7 @@ func (bs *FileBackingStore) CommandSubmit(cmd *api.SCSICommand) (err error) {
doWrite = true
goto write
case api.SYNCHRONIZE_CACHE, api.SYNCHRONIZE_CACHE_16:
if err = util.Fdatasync(lu.File); err != nil {
if err = util.Fdatasync(bs.File); err != nil {
panic(err)
}
break
@@ -113,7 +123,7 @@ func (bs *FileBackingStore) CommandSubmit(cmd *api.SCSICommand) (err error) {
// TODO
break
case api.READ_6, api.READ_10, api.READ_12, api.READ_16:
length, err = lu.File.ReadAt(rbuf, int64(offset))
length, err = bs.File.ReadAt(rbuf, int64(offset))
if err != nil && err != io.EOF {
key = scsi.MEDIUM_ERROR
asc = scsi.ASC_READ_ERROR
@@ -124,11 +134,11 @@ func (bs *FileBackingStore) CommandSubmit(cmd *api.SCSICommand) (err error) {
}
if (opcode != api.READ_6) && (scb[1]&0x10 != 0) {
util.Fadvise(lu.File, int64(offset), int64(length), util.POSIX_FADV_NOREUSE)
util.Fadvise(bs.File, int64(offset), int64(length), util.POSIX_FADV_NOREUSE)
}
cmd.InSDBBuffer.Buffer = bytes.NewBuffer(rbuf)
case api.PRE_FETCH_10, api.PRE_FETCH_16:
err = util.Fadvise(lu.File, int64(offset), int64(cmd.TL), util.POSIX_FADV_WILLNEED)
err = util.Fadvise(bs.File, int64(offset), int64(cmd.TL), util.POSIX_FADV_WILLNEED)
if err != nil {
key = scsi.MEDIUM_ERROR
asc = scsi.ASC_READ_ERROR
@@ -144,7 +154,7 @@ func (bs *FileBackingStore) CommandSubmit(cmd *api.SCSICommand) (err error) {
write:
if doWrite {
// hack: wbuf = []byte("hello world!")
length, err = lu.File.WriteAt(wbuf, int64(offset))
length, err = bs.File.WriteAt(wbuf, int64(offset))
if err != nil || length != len(wbuf) {
glog.Error(err)
key = scsi.MEDIUM_ERROR
@@ -165,7 +175,7 @@ write:
goto sense
}
if ((opcode != api.WRITE_6) && (scb[1]&0x8 != 0)) || (pg.Data[0]&0x04 == 0) {
if err = util.Fdatasync(lu.File); err != nil {
if err = util.Fdatasync(bs.File); err != nil {
key = scsi.MEDIUM_ERROR
asc = scsi.ASC_READ_ERROR
goto sense
@@ -173,12 +183,12 @@ write:
}
if (opcode != api.WRITE_6) && (scb[1]&0x10 != 0) {
util.Fadvise(lu.File, int64(offset), int64(length), util.POSIX_FADV_NOREUSE)
util.Fadvise(bs.File, int64(offset), int64(length), util.POSIX_FADV_NOREUSE)
}
}
verify:
if doVerify {
length, err = lu.File.ReadAt(rbuf, int64(offset))
length, err = bs.File.ReadAt(rbuf, int64(offset))
if length != len(rbuf) {
key = scsi.MEDIUM_ERROR
asc = scsi.ASC_READ_ERROR
@@ -191,7 +201,7 @@ verify:
goto sense
}
if scb[1]&0x10 != 0 {
util.Fadvise(lu.File, int64(offset), int64(length), util.POSIX_FADV_WILLNEED)
util.Fadvise(bs.File, int64(offset), int64(length), util.POSIX_FADV_WILLNEED)
}
}
glog.Infof("io done %s", string(scb))

View File

@@ -17,8 +17,6 @@ limitations under the License.
package backingstore
import (
"os"
"github.com/gostor/gotgt/pkg/api"
"github.com/gostor/gotgt/pkg/scsi"
)
@@ -41,8 +39,8 @@ func newNull() (api.BackingStore, error) {
}, nil
}
func (bs *NullBackingStore) Open(dev *api.SCSILu, path string) (*os.File, error) {
return nil, nil
func (bs *NullBackingStore) Open(dev *api.SCSILu, path string) error {
return nil
}
func (bs *NullBackingStore) Close(dev *api.SCSILu) error {
@@ -57,6 +55,10 @@ func (bs *NullBackingStore) Exit(dev *api.SCSILu) error {
return nil
}
func (bs *NullBackingStore) Size(dev *api.SCSILu) uint64 {
return 0
}
func (bs *NullBackingStore) CommandSubmit(cmd *api.SCSICommand) error {
cmd.Result = api.SAM_STAT_GOOD
return nil

View File

@@ -17,36 +17,44 @@ limitations under the License.
package scsi
import (
"os"
"errors"
"strings"
"github.com/gostor/gotgt/pkg/api"
)
func NewSCSILu(lun uint64, target *api.SCSITarget, file string) (*api.SCSILu, error) {
/*
* path format <protocol>:/absolute/file/path
*/
func NewSCSILu(device_uuid uint64, path string) (*api.SCSILu, error) {
pathinfo := strings.SplitN(path, ":", 2)
if len(pathinfo) < 2 {
return nil, errors.New("invalid device path string")
}
backendType := pathinfo[0]
backendPath := pathinfo[1]
sbc := NewSBCDevice()
backing, err := NewBackingStore("file")
backing, err := NewBackingStore(backendType)
if err != nil {
return nil, err
}
var lu = &api.SCSILu{
Lun: lun,
Target: target,
Lun: 0,
PerformCommand: luPerformCommand,
DeviceProtocol: sbc,
Storage: backing,
BlockShift: api.DefaultBlockShift,
}
// hack this
if finfo, err := os.Stat(file); err != nil {
return nil, err
} else {
lu.Size = uint64(finfo.Size())
}
f, err := backing.Open(lu, file)
err = backing.Open(lu, backendPath)
if err != nil {
return nil, err
}
lu.File = f
lu.Size = backing.Size(lu)
lu.DeviceProtocol.InitLu(lu)
lu.Attrs.Online = true
lu.Attrs.Lbppbe = 3

View File

@@ -45,7 +45,6 @@ func (sbc SBCSCSIDeviceProtocol) PerformCommand(opcode int) interface{} {
}
func (sbc SBCSCSIDeviceProtocol) InitLu(lu *api.SCSILu) error {
var tgt = lu.Target
// init LU's phy attribute
lu.Attrs.DeviceType = api.TYPE_DISK
lu.Attrs.Qualifier = false
@@ -55,8 +54,12 @@ func (sbc SBCSCSIDeviceProtocol) InitLu(lu *api.SCSILu) error {
lu.Attrs.SWP = false
lu.Attrs.SenseFormat = false
lu.Attrs.VendorID = "GOSTOR"
lu.Attrs.SCSIID = fmt.Sprintf("GOSTOR %x%d", tgt.TID, lu.Lun)
lu.Attrs.SCSISN = fmt.Sprintf("beaf%d%d", tgt.TID, lu.Lun)
/*
lu.Attrs.SCSIID = fmt.Sprintf("GOSTOR %x%d", tgt.TID, lu.Lun)
lu.Attrs.SCSISN = fmt.Sprintf("beaf%d%d", tgt.TID, lu.Lun)
*/
lu.Attrs.SCSIID = fmt.Sprintf("GOSTOR%d", lu.Lun)
lu.Attrs.SCSISN = fmt.Sprintf("beaf%d", lu.Lun)
lu.Attrs.ProductID = "VIRTUAL-DISK"
lu.Attrs.VersionDesction = []uint16{
0x04C0, // SBC-3 no version claimed

View File

@@ -75,7 +75,11 @@ func (s *SCSITargetService) AddCommandQueue(tid int, scmd *api.SCSICommand) erro
}
scmd.ITNexus = itn
/*
* TODO: scmd.Device = target.Devices[util.GetUnalignedUint64(scmd.Lun[:])]
*/
scmd.Device = target.Devices[0]
glog.V(2).Infof("scsi opcode: 0x%x, LUN: %d:", int(scmd.SCB.Bytes()[0]), binary.LittleEndian.Uint64(scmd.Lun[:]))
result := scmd.Device.PerformCommand(tid, scmd)
scmd.Result = result.Stat
if result.Err != nil {

89
pkg/scsi/scsilumap.go Normal file
View 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.
*/
package scsi
import (
"errors"
"strconv"
"sync"
"github.com/gostor/gotgt/pkg/api"
"github.com/gostor/gotgt/pkg/config"
)
type BackendType string
type SCSILUMap struct {
mutex sync.RWMutex
AllDevices api.LUNMap /* use UUID as the key for all LUs*/
TargetsLUNMap map[string]api.LUNMap /* use target name as the key for target's LUN map*/
}
var globalSCSILUMap = SCSILUMap{AllDevices: make(api.LUNMap), TargetsLUNMap: make(map[string]api.LUNMap)}
func mappingLUN(deviceID uint64, lun uint64, target string) {
device := globalSCSILUMap.AllDevices[deviceID]
lunMap := globalSCSILUMap.TargetsLUNMap[target]
if lunMap == nil {
globalSCSILUMap.TargetsLUNMap[target] = make(api.LUNMap)
lunMap = globalSCSILUMap.TargetsLUNMap[target]
}
lunMap[lun] = device
}
func GetLU(tgtName string, LUN uint64) *api.SCSILu {
globalSCSILUMap.mutex.RLock()
defer globalSCSILUMap.mutex.RUnlock()
lunMap := globalSCSILUMap.TargetsLUNMap[tgtName]
lun := lunMap[LUN]
return lun
}
func GetTargetLUNMap(tgtName string) api.LUNMap {
globalSCSILUMap.mutex.RLock()
defer globalSCSILUMap.mutex.RUnlock()
lunMap := globalSCSILUMap.TargetsLUNMap[tgtName]
return lunMap
}
func InitSCSILUMap(config *config.Config) error {
globalSCSILUMap.mutex.Lock()
defer globalSCSILUMap.mutex.Unlock()
for _, bs := range config.Storages {
lu, err := NewSCSILu(bs.DeviceID, bs.Path)
if err != nil {
return errors.New("Init SCSI LU map error.")
}
globalSCSILUMap.AllDevices[bs.DeviceID] = lu
}
for tgtName, tgt := range config.Targets {
for lunstr, deviceID := range tgt.LUNs {
lun, err := strconv.ParseUint(lunstr, 10, 64)
if err != nil {
return errors.New("LU Number must be a number")
}
mappingLUN(deviceID, lun, tgtName)
}
}
return nil
}

View File

@@ -146,6 +146,7 @@ func SPCInquiry(host int, cmd *api.SCSICommand) api.SAMStat {
b = (uint8(0) & 0x7) << 5
b |= uint8(0) & 0x1f
}
fmt.Println(cmd.Device.Lun, *(*uint64)(unsafe.Pointer(&cmd.Lun)))
if cmd.Device.Lun != *(*uint64)(unsafe.Pointer(&cmd.Lun)) {
goto sense
}
@@ -235,7 +236,8 @@ func SPCReportLuns(host int, cmd *api.SCSICommand) api.SAMStat {
buf.WriteByte(0x00)
}
for _, lu := range cmd.Target.Devices {
for lunumber, lu := range cmd.Target.Devices {
fmt.Println("LUN:", lunumber)
if remainLength > 0 {
lun := lu.Lun
if lun > 0xff {

View File

@@ -23,30 +23,19 @@ import (
"github.com/gostor/gotgt/pkg/api"
)
func (s *SCSITargetService) NewSCSITarget(tid int, driverName, name string, luns []string) (*api.SCSITarget, error) {
func (s *SCSITargetService) NewSCSITarget(tid int, driverName, name string) (*api.SCSITarget, error) {
// verify the target ID
// verify the target's Name
// verify the low level driver
var target = &api.SCSITarget{
Name: name,
TID: tid,
Devices: []*api.SCSILu{},
Name: name,
TID: tid,
}
var devices = []*api.SCSILu{}
for i, ln := range luns {
lun, err := NewSCSILu(uint64(i), target, ln)
if err != nil {
glog.Errorf("fail to create LU: %v", err)
return nil, err
}
devices = append(devices, lun)
}
s.mutex.Lock()
target.Devices = devices
s.Targets = append(s.Targets, target)
s.mutex.Unlock()
target.Devices = GetTargetLUNMap(target.Name)
return target, nil
}