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

@@ -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
}