mapping lun and fix portal management
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
89
pkg/scsi/scsilumap.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.
|
||||
*/
|
||||
|
||||
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
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user