fix bugs and make it run basically
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2015 The GoStor Authors All rights reserved.
|
||||
Copyright 2016 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.
|
||||
@@ -18,6 +18,7 @@ package scsi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/gostor/gotgt/pkg/api"
|
||||
)
|
||||
@@ -28,15 +29,7 @@ type BaseBackingStore struct {
|
||||
OflagsSupported int
|
||||
}
|
||||
|
||||
type BackingStore interface {
|
||||
Open(dev *api.SCSILu, path string, fd *int, size *uint64) error
|
||||
Close(dev *api.SCSILu) error
|
||||
Init(dev *api.SCSILu, Opts string) error
|
||||
Exit(dev *api.SCSILu) error
|
||||
CommandSubmit(cmd *api.SCSICommand) error
|
||||
}
|
||||
|
||||
type BackingStoreFunc func() (BackingStore, error)
|
||||
type BackingStoreFunc func() (api.BackingStore, error)
|
||||
|
||||
var registeredPlugins = map[string](BackingStoreFunc){}
|
||||
|
||||
@@ -44,7 +37,7 @@ func RegisterBackingStore(name string, f BackingStoreFunc) {
|
||||
registeredPlugins[name] = f
|
||||
}
|
||||
|
||||
func NewBackingStore(name string) (BackingStore, error) {
|
||||
func NewBackingStore(name string) (api.BackingStore, error) {
|
||||
if name == "" {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -59,8 +52,8 @@ type fakeBackingStore struct {
|
||||
BaseBackingStore
|
||||
}
|
||||
|
||||
func (fake *fakeBackingStore) Open(dev *api.SCSILu, path string, fd *int, size *uint64) error {
|
||||
return nil
|
||||
func (fake *fakeBackingStore) Open(dev *api.SCSILu, path string) (*os.File, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (fake *fakeBackingStore) Close(dev *api.SCSILu) error {
|
||||
|
||||
+165
-17
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2015 The GoStor Authors All rights reserved.
|
||||
Copyright 2016 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.
|
||||
@@ -16,40 +16,188 @@ limitations under the License.
|
||||
|
||||
package backingstore
|
||||
|
||||
import "github.com/gostor/gotgt/pkg/scsi"
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/gostor/gotgt/pkg/api"
|
||||
"github.com/gostor/gotgt/pkg/scsi"
|
||||
"github.com/gostor/gotgt/pkg/util"
|
||||
)
|
||||
|
||||
func init() {
|
||||
scsi.RegisterBackingStore("file", new)
|
||||
}
|
||||
|
||||
type FileBackingStore struct {
|
||||
BaseBackingStore
|
||||
scsi.BaseBackingStore
|
||||
}
|
||||
|
||||
func new() (scsi.BackingStore, error) {
|
||||
return NullBackingStore{
|
||||
Name: "file",
|
||||
DataSize: 0,
|
||||
OflagsSupported: 0,
|
||||
func new() (api.BackingStore, error) {
|
||||
return &FileBackingStore{
|
||||
BaseBackingStore: scsi.BaseBackingStore{
|
||||
Name: "file",
|
||||
DataSize: 0,
|
||||
OflagsSupported: 0,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (bs *FileBackingStore) Open(dev *SCSILu, path string, fd *int, size *uint64) error {
|
||||
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
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func (bs *FileBackingStore) Close(dev *api.SCSILu) error {
|
||||
return dev.File.Close()
|
||||
}
|
||||
|
||||
func (bs *FileBackingStore) Init(dev *api.SCSILu, Opts string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bs *FileBackingStore) Close(dev *SCSILu) error {
|
||||
func (bs *FileBackingStore) Exit(dev *api.SCSILu) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bs *FileBackingStore) Init(dev *SCSILu, Opts string) error {
|
||||
return nil
|
||||
}
|
||||
func (bs *FileBackingStore) CommandSubmit(cmd *api.SCSICommand) (err error) {
|
||||
var (
|
||||
scb = cmd.SCB.Bytes()
|
||||
offset = cmd.Offset
|
||||
opcode = api.SCSICommandType(scb[0])
|
||||
lu = cmd.Device
|
||||
key = scsi.ILLEGAL_REQUEST
|
||||
asc = scsi.ASC_INVALID_FIELD_IN_CDB
|
||||
wbuf []byte = []byte{}
|
||||
rbuf []byte = []byte{}
|
||||
length int
|
||||
doVerify bool = false
|
||||
doWrite bool = false
|
||||
)
|
||||
switch opcode {
|
||||
case api.ORWRITE_16:
|
||||
tmpbuf := []byte{}
|
||||
length, err = lu.File.ReadAt(tmpbuf, int64(offset))
|
||||
if length != len(tmpbuf) {
|
||||
key = scsi.MEDIUM_ERROR
|
||||
asc = scsi.ASC_READ_ERROR
|
||||
break
|
||||
}
|
||||
cmd.InSDBBuffer.Buffer = bytes.NewBuffer(tmpbuf)
|
||||
|
||||
func (bs *FileBackingStore) Exit(dev *SCSILu) error {
|
||||
return nil
|
||||
}
|
||||
wbuf = cmd.OutSDBBuffer.Buffer.Bytes()
|
||||
doWrite = true
|
||||
goto write
|
||||
case api.COMPARE_AND_WRITE:
|
||||
// TODO
|
||||
doWrite = true
|
||||
goto write
|
||||
case api.SYNCHRONIZE_CACHE, api.SYNCHRONIZE_CACHE_16:
|
||||
break
|
||||
case api.WRITE_VERIFY, api.WRITE_VERIFY_12, api.WRITE_VERIFY_16:
|
||||
doVerify = true
|
||||
case api.WRITE_6, api.WRITE_10, api.WRITE_12, api.WRITE_16:
|
||||
wbuf = cmd.OutSDBBuffer.Buffer.Bytes()
|
||||
doWrite = true
|
||||
goto write
|
||||
case api.WRITE_SAME, api.WRITE_SAME_16:
|
||||
// TODO
|
||||
break
|
||||
case api.READ_6, api.READ_10, api.READ_12, api.READ_16:
|
||||
length, err = lu.File.ReadAt(rbuf, int64(offset))
|
||||
if err != nil {
|
||||
key = scsi.MEDIUM_ERROR
|
||||
asc = scsi.ASC_READ_ERROR
|
||||
break
|
||||
}
|
||||
for i := 0; i < int(cmd.TL)-length; i++ {
|
||||
rbuf = append(rbuf, 0)
|
||||
}
|
||||
|
||||
if (opcode != api.READ_6) && (scb[1]&0x10 != 0) {
|
||||
util.Fadvise(lu.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)
|
||||
if err != nil {
|
||||
key = scsi.MEDIUM_ERROR
|
||||
asc = scsi.ASC_READ_ERROR
|
||||
}
|
||||
case api.VERIFY_10, api.VERIFY_12, api.VERIFY_16:
|
||||
doVerify = true
|
||||
goto verify
|
||||
case api.UNMAP:
|
||||
// TODO
|
||||
default:
|
||||
break
|
||||
}
|
||||
write:
|
||||
if doWrite {
|
||||
// hack: wbuf = []byte("hello world!")
|
||||
length, err = lu.File.WriteAt(wbuf, int64(offset))
|
||||
if err != nil || length != len(wbuf) {
|
||||
glog.Error(err)
|
||||
key = scsi.MEDIUM_ERROR
|
||||
asc = scsi.ASC_READ_ERROR
|
||||
goto sense
|
||||
}
|
||||
glog.V(2).Infof("write data at %d for length %d", offset, length)
|
||||
var pg *api.ModePage
|
||||
for _, p := range lu.ModePages {
|
||||
if p.Pcode == 0x08 && p.SubPcode == 0 {
|
||||
pg = &p
|
||||
break
|
||||
}
|
||||
}
|
||||
if pg == nil {
|
||||
key = scsi.ILLEGAL_REQUEST
|
||||
asc = scsi.ASC_INVALID_FIELD_IN_CDB
|
||||
goto sense
|
||||
}
|
||||
if ((opcode != api.WRITE_6) && (scb[1]&0x8 != 0)) || (pg.Data[0]&0x04 == 0) {
|
||||
if err = util.Fdatasync(lu.File); err != nil {
|
||||
key = scsi.MEDIUM_ERROR
|
||||
asc = scsi.ASC_READ_ERROR
|
||||
goto sense
|
||||
}
|
||||
}
|
||||
|
||||
if (opcode != api.WRITE_6) && (scb[1]&0x10 != 0) {
|
||||
util.Fadvise(lu.File, int64(offset), int64(length), util.POSIX_FADV_NOREUSE)
|
||||
}
|
||||
}
|
||||
verify:
|
||||
if doVerify {
|
||||
length, err = lu.File.ReadAt(rbuf, int64(offset))
|
||||
if length != len(rbuf) {
|
||||
key = scsi.MEDIUM_ERROR
|
||||
asc = scsi.ASC_READ_ERROR
|
||||
goto sense
|
||||
}
|
||||
if !bytes.Equal(cmd.OutSDBBuffer.Buffer.Bytes(), rbuf) {
|
||||
err = fmt.Errorf("verify fail between out buffer and read buffer")
|
||||
key = scsi.MISCOMPARE
|
||||
asc = scsi.ASC_MISCOMPARE_DURING_VERIFY_OPERATION
|
||||
goto sense
|
||||
}
|
||||
if scb[1]&0x10 != 0 {
|
||||
util.Fadvise(lu.File, int64(offset), int64(length), util.POSIX_FADV_WILLNEED)
|
||||
}
|
||||
}
|
||||
glog.Infof("io done %s", string(scb))
|
||||
sense:
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return err
|
||||
}
|
||||
_ = key
|
||||
_ = asc
|
||||
|
||||
func (bs *FileBackingStore) CommandSubmit(cmd *SCSICommand) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -17,45 +17,47 @@ limitations under the License.
|
||||
package backingstore
|
||||
|
||||
import (
|
||||
"github.com/gostor/gotgt/pkg/scsi"
|
||||
"os"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/gostor/gotgt/pkg/api"
|
||||
"github.com/gostor/gotgt/pkg/scsi"
|
||||
)
|
||||
|
||||
func init() {
|
||||
scsi.RegisterBackingStore("null", new)
|
||||
scsi.RegisterBackingStore("null", newNull)
|
||||
}
|
||||
|
||||
type NullBackingStore struct {
|
||||
BaseBackingStore
|
||||
scsi.BaseBackingStore
|
||||
}
|
||||
|
||||
func new() (scsi.BackingStore, error) {
|
||||
return NullBackingStore{
|
||||
Name: "null",
|
||||
DataSize: 0,
|
||||
OflagsSupported: 0,
|
||||
func newNull() (api.BackingStore, error) {
|
||||
return &NullBackingStore{
|
||||
BaseBackingStore: scsi.BaseBackingStore{
|
||||
Name: "null",
|
||||
DataSize: 0,
|
||||
OflagsSupported: 0,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (bs *NullBackingStore) Open(dev *SCSILu, path string, fd *int, size *uint64) error {
|
||||
glog.V(1).Infof("NULL backing store open, size: %d", size)
|
||||
func (bs *NullBackingStore) Open(dev *api.SCSILu, path string) (*os.File, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (bs *NullBackingStore) Close(dev *api.SCSILu) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bs *NullBackingStore) Close(dev *SCSILu) error {
|
||||
func (bs *NullBackingStore) Init(dev *api.SCSILu, Opts string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bs *NullBackingStore) Init(dev *SCSILu, Opts string) error {
|
||||
func (bs *NullBackingStore) Exit(dev *api.SCSILu) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bs *NullBackingStore) Exit(dev *SCSILu) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bs *NullBackingStore) CommandSubmit(cmd *SCSICommand) error {
|
||||
cmd.Result = SAM_STAT_GOOD
|
||||
func (bs *NullBackingStore) CommandSubmit(cmd *api.SCSICommand) error {
|
||||
cmd.Result = api.SAM_STAT_GOOD
|
||||
return nil
|
||||
}
|
||||
|
||||
+42
-10
@@ -16,19 +16,51 @@ limitations under the License.
|
||||
|
||||
package scsi
|
||||
|
||||
import "github.com/gostor/gotgt/pkg/api"
|
||||
import (
|
||||
"os"
|
||||
|
||||
type SCSILuOps struct {
|
||||
*api.SCSILu
|
||||
"github.com/gostor/gotgt/pkg/api"
|
||||
)
|
||||
|
||||
DeviceProtocol SCSIDeviceProtocol
|
||||
Storage *BackingStore
|
||||
Target *api.SCSITarget
|
||||
Attrs api.SCSILuPhyAttribute
|
||||
func NewSCSILu(lun uint64, target *api.SCSITarget) (*api.SCSILu, error) {
|
||||
sbc := NewSBCDevice()
|
||||
backing, err := NewBackingStore("file")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var lu = &api.SCSILu{
|
||||
Lun: lun,
|
||||
Target: target,
|
||||
PerformCommand: luPerformCommand,
|
||||
DeviceProtocol: sbc,
|
||||
Storage: backing,
|
||||
BlockShift: 0,
|
||||
Size: 1024 * 1024 * 1024,
|
||||
}
|
||||
// hack this
|
||||
if _, err = os.Stat("/tmp/data.txt"); err != nil && os.IsExist(err) {
|
||||
os.Create("/tmp/data.txt")
|
||||
}
|
||||
f, err := backing.Open(lu, "/tmp/data.txt")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
lu.File = f
|
||||
lu.DeviceProtocol.InitLu(lu)
|
||||
lu.Attrs.Online = true
|
||||
return lu, nil
|
||||
}
|
||||
|
||||
// function handler for command performing and finishing
|
||||
PerformCommand CommandFunc
|
||||
FinishCommand func(*api.SCSITarget, *api.SCSICommand)
|
||||
func luPerformCommand(tid int, cmd *api.SCSICommand) api.SAMStat {
|
||||
op := int(cmd.SCB.Bytes()[0])
|
||||
fn := cmd.Device.DeviceProtocol.PerformCommand(op)
|
||||
if fn != nil {
|
||||
fnop := fn.(SCSIDeviceOperation)
|
||||
// host := cmd.ITNexus.Host
|
||||
host := 0
|
||||
return fnop.CommandPerformFunc(host, cmd)
|
||||
}
|
||||
return api.SAMStatGood
|
||||
}
|
||||
|
||||
func luPreventRemoval(lu *api.SCSILu) bool {
|
||||
|
||||
+224
-27
@@ -18,9 +18,13 @@ limitations under the License.
|
||||
package scsi
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/gostor/gotgt/pkg/api"
|
||||
"github.com/gostor/gotgt/pkg/util"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -36,30 +40,75 @@ type SBCSCSIDeviceProtocol struct {
|
||||
BaseSCSIDeviceProtocol
|
||||
}
|
||||
|
||||
func (sbc *SBCSCSIDeviceProtocol) InitLu(lu *api.SCSILu) error {
|
||||
return nil
|
||||
func (sbc SBCSCSIDeviceProtocol) PerformCommand(opcode int) interface{} {
|
||||
return sbc.SCSIDeviceOps[opcode]
|
||||
}
|
||||
func (sbc *SBCSCSIDeviceProtocol) ExitLu(lu *api.SCSILu) error {
|
||||
return nil
|
||||
}
|
||||
func (sbc *SBCSCSIDeviceProtocol) ConfigLu(lu *api.SCSILu) error {
|
||||
return nil
|
||||
}
|
||||
func (sbc *SBCSCSIDeviceProtocol) OnlineLu(lu *api.SCSILu) error {
|
||||
return nil
|
||||
}
|
||||
func (sbc *SBCSCSIDeviceProtocol) OfflineLu(lu *api.SCSILu) error {
|
||||
|
||||
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
|
||||
lu.Attrs.Thinprovisioning = false
|
||||
lu.Attrs.Removable = false
|
||||
lu.Attrs.Readonly = false
|
||||
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.ProductID = "VIRTUAL-DISK"
|
||||
lu.Attrs.VersionDesction = []uint16{
|
||||
0x04C0, // SBC-3 no version claimed
|
||||
0x0960, // iSCSI
|
||||
0x0300, // SPC-3
|
||||
}
|
||||
if lu.BlockShift == 0 {
|
||||
lu.BlockShift = api.DefaultBlockShift
|
||||
}
|
||||
pages := []api.ModePage{}
|
||||
// Vendor uniq - However most apps seem to call for mode page 0
|
||||
pages = append(pages, api.ModePage{0, 0, []byte{}})
|
||||
// Disconnect page
|
||||
pages = append(pages, api.ModePage{2, 0, []byte{0x80, 0x80, 0, 0xa, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}})
|
||||
// Caching Page
|
||||
pages = append(pages, api.ModePage{8, 0, []byte{0x14, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}})
|
||||
|
||||
// Control page
|
||||
pages = append(pages, api.ModePage{0x0a, 0, []byte{2, 0x10, 0, 0, 0, 0, 0, 0, 2, 0}})
|
||||
|
||||
// Control Extensions mode page: TCMOS:1
|
||||
pages = append(pages, api.ModePage{0x0a, 1, []byte{0x04, 0x00, 0x00}})
|
||||
// Informational Exceptions Control page
|
||||
pages = append(pages, api.ModePage{0x1c, 0, []byte{8, 0, 0, 0, 0, 0, 0, 0, 0, 0}})
|
||||
lu.ModePages = pages
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewSBCDevice() SBCSCSIDeviceProtocol {
|
||||
func (sbc SBCSCSIDeviceProtocol) ConfigLu(lu *api.SCSILu) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sbc SBCSCSIDeviceProtocol) OnlineLu(lu *api.SCSILu) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sbc SBCSCSIDeviceProtocol) OfflineLu(lu *api.SCSILu) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sbc SBCSCSIDeviceProtocol) ExitLu(lu *api.SCSILu) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewSBCDevice() api.SCSIDeviceProtocol {
|
||||
var sbc = SBCSCSIDeviceProtocol{
|
||||
BaseSCSIDeviceProtocol{
|
||||
Type: api.TYPE_DISK,
|
||||
SCSIDeviceOps: make([]SCSIDeviceOperation, 256),
|
||||
SCSIDeviceOps: []SCSIDeviceOperation{},
|
||||
},
|
||||
}
|
||||
for i := 0; i <= 256; i++ {
|
||||
for i := 0; i < 256; i++ {
|
||||
sbc.SCSIDeviceOps = append(sbc.SCSIDeviceOps, NewSCSIDeviceOperation(SPCIllegalOp, nil, 0))
|
||||
}
|
||||
sbc.SCSIDeviceOps[api.TEST_UNIT_READY] = NewSCSIDeviceOperation(SPCTestUnit, nil, 0)
|
||||
@@ -103,9 +152,10 @@ func NewSBCDevice() SBCSCSIDeviceProtocol {
|
||||
sbc.SCSIDeviceOps[api.PRE_FETCH_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN)
|
||||
sbc.SCSIDeviceOps[api.SYNCHRONIZE_CACHE_16] = NewSCSIDeviceOperation(SBCSyncCache, nil, PR_EA_FA|PR_EA_FN|PR_WE_FA|PR_WE_FN)
|
||||
sbc.SCSIDeviceOps[api.WRITE_SAME_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, 0)
|
||||
sbc.SCSIDeviceOps[api.SERVICE_ACTION_IN] = NewSCSIDeviceOperation(SPCServiceAction, nil, 0)
|
||||
sbc.SCSIDeviceOps[api.SERVICE_ACTION_IN] = NewSCSIDeviceOperation(SBCServiceAction, nil, 0)
|
||||
|
||||
sbc.SCSIDeviceOps[api.REPORT_LUNS] = NewSCSIDeviceOperation(SPCReportLuns, nil, 0)
|
||||
sbc.SCSIDeviceOps[api.MAINT_PROTOCOL_IN] = NewSCSIDeviceOperation(SPCServiceAction, nil, 0)
|
||||
sbc.SCSIDeviceOps[api.EXCHANGE_MEDIUM] = NewSCSIDeviceOperation(SPCServiceAction, nil, 0)
|
||||
sbc.SCSIDeviceOps[api.READ_12] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN)
|
||||
sbc.SCSIDeviceOps[api.WRITE_12] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_WE_FA|PR_EA_FA|PR_WE_FA|PR_WE_FN)
|
||||
@@ -132,15 +182,18 @@ func SBCModeSense(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
deviceSpecific |= 0x80
|
||||
}
|
||||
|
||||
data := cmd.InSDBBuffer.Buffer
|
||||
data.Next(2)
|
||||
buf := cmd.InSDBBuffer.Buffer
|
||||
data := []byte{0x00, 0x00, 0x00, 0x00}
|
||||
if buf != nil {
|
||||
data = buf.Bytes()
|
||||
}
|
||||
|
||||
if cmd.SCB.Bytes()[0] == 0x1a {
|
||||
data.WriteByte(deviceSpecific)
|
||||
data[2] = deviceSpecific
|
||||
} else {
|
||||
data.Next(1)
|
||||
data.WriteByte(deviceSpecific)
|
||||
data[3] = deviceSpecific
|
||||
}
|
||||
cmd.InSDBBuffer.Buffer = bytes.NewBuffer(data)
|
||||
|
||||
return api.SAMStatGood
|
||||
}
|
||||
@@ -196,7 +249,135 @@ func SBCUnmap(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
}
|
||||
|
||||
func SBCReadWrite(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
return api.SAMStatGood
|
||||
var (
|
||||
key = ILLEGAL_REQUEST
|
||||
asc = ASC_INVALID_FIELD_IN_CDB
|
||||
dev = cmd.Device
|
||||
scb = cmd.SCB.Bytes()
|
||||
opcode = api.SCSICommandType(scb[0])
|
||||
lba uint64
|
||||
tl uint32
|
||||
err error
|
||||
)
|
||||
if dev.Attrs.Removable && !dev.Attrs.Online {
|
||||
key = NOT_READY
|
||||
asc = ASC_MEDIUM_NOT_PRESENT
|
||||
glog.Warningf("sense")
|
||||
goto sense
|
||||
}
|
||||
|
||||
switch opcode {
|
||||
case api.READ_10, api.READ_12, api.READ_16, api.WRITE_10, api.WRITE_12, api.WRITE_16, api.ORWRITE_16,
|
||||
api.WRITE_VERIFY, api.WRITE_VERIFY_12, api.WRITE_VERIFY_16, api.COMPARE_AND_WRITE:
|
||||
// We only support protection information type 0
|
||||
/*
|
||||
if scb[1]&0xe0 != 0 {
|
||||
key = ILLEGAL_REQUEST
|
||||
asc = ASC_INVALID_FIELD_IN_CDB
|
||||
glog.Warningf("sense")
|
||||
goto sense
|
||||
}
|
||||
*/
|
||||
if cmd.OutSDBBuffer.Buffer == nil {
|
||||
cmd.OutSDBBuffer.Buffer = &bytes.Buffer{}
|
||||
}
|
||||
case api.WRITE_SAME, api.WRITE_SAME_16:
|
||||
// We dont support resource-provisioning so ANCHOR bit == 1 is an error.
|
||||
if scb[1]&0x10 != 0 {
|
||||
key = ILLEGAL_REQUEST
|
||||
asc = ASC_INVALID_FIELD_IN_CDB
|
||||
goto sense
|
||||
}
|
||||
// We only support unmap for thin provisioned LUNS
|
||||
if (scb[1]&0x08 != 0) && !dev.Attrs.Thinprovisioning {
|
||||
key = ILLEGAL_REQUEST
|
||||
asc = ASC_INVALID_FIELD_IN_CDB
|
||||
goto sense
|
||||
}
|
||||
// We only support protection information type 0
|
||||
if scb[1]&0xe0 != 0 {
|
||||
key = ILLEGAL_REQUEST
|
||||
asc = ASC_INVALID_FIELD_IN_CDB
|
||||
goto sense
|
||||
}
|
||||
// LBDATA and PBDATA can not both be set
|
||||
if (scb[1] & 0x06) == 0x06 {
|
||||
key = ILLEGAL_REQUEST
|
||||
asc = ASC_INVALID_FIELD_IN_CDB
|
||||
goto sense
|
||||
}
|
||||
}
|
||||
|
||||
if dev.Attrs.Readonly || dev.Attrs.SWP {
|
||||
switch opcode {
|
||||
case api.WRITE_6, api.WRITE_10, api.WRITE_12, api.WRITE_16, api.ORWRITE_16,
|
||||
api.WRITE_VERIFY, api.WRITE_VERIFY_12, api.WRITE_VERIFY_16, api.WRITE_SAME, api.WRITE_SAME_16,
|
||||
api.PRE_FETCH_10, api.PRE_FETCH_16, api.COMPARE_AND_WRITE:
|
||||
key = DATA_PROTECT
|
||||
asc = ASC_WRITE_PROTECT
|
||||
glog.Warningf("sense")
|
||||
goto sense
|
||||
}
|
||||
}
|
||||
|
||||
lba = getSCSIReadWriteOffset(scb)
|
||||
tl = getSCSIReadWriteCount(scb)
|
||||
|
||||
// Verify that we are not doing i/o beyond the end-of-lun
|
||||
if tl != 0 {
|
||||
if lba+uint64(tl) < lba || lba+uint64(tl) > dev.Size>>dev.BlockShift {
|
||||
key = ILLEGAL_REQUEST
|
||||
asc = ASC_LBA_OUT_OF_RANGE
|
||||
glog.Warningf("sense: lba: %d, tl: %d, size: %d", lba, tl, dev.Size>>dev.BlockShift)
|
||||
goto sense
|
||||
}
|
||||
} else {
|
||||
if lba >= dev.Size>>dev.BlockShift {
|
||||
key = ILLEGAL_REQUEST
|
||||
asc = ASC_LBA_OUT_OF_RANGE
|
||||
glog.Warningf("sense")
|
||||
goto sense
|
||||
}
|
||||
}
|
||||
|
||||
cmd.Offset = lba << dev.BlockShift
|
||||
cmd.TL = tl << dev.BlockShift
|
||||
|
||||
// Handle residuals
|
||||
switch opcode {
|
||||
case api.READ_6, api.READ_10, api.READ_12, api.READ_16:
|
||||
/*
|
||||
if (cmd->tl != scsi_get_in_length(cmd))
|
||||
scsi_set_in_resid_by_actual(cmd, cmd->tl);
|
||||
*/
|
||||
case api.WRITE_6, api.WRITE_10, api.WRITE_12, api.WRITE_16, api.WRITE_VERIFY, api.WRITE_VERIFY_12, api.WRITE_VERIFY_16:
|
||||
/*
|
||||
if (cmd->tl != scsi_get_out_length(cmd)) {
|
||||
scsi_set_out_resid_by_actual(cmd, cmd->tl);
|
||||
|
||||
/* We need to clamp the size of the in-buffer
|
||||
* so that we dont try to write > cmd->tl in the
|
||||
* backend store.
|
||||
*
|
||||
if (cmd->tl < scsi_get_out_length(cmd)) {
|
||||
scsi_set_out_length(cmd, cmd->tl);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
err = dev.Storage.CommandSubmit(cmd)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
key = HARDWARE_ERROR
|
||||
asc = ASC_INTERNAL_TGT_FAILURE
|
||||
} else {
|
||||
return api.SAMStatGood
|
||||
}
|
||||
|
||||
sense:
|
||||
BuildSenseData(cmd, key, asc)
|
||||
return api.SAMStatCheckCondition
|
||||
}
|
||||
|
||||
func SBCReserve(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
@@ -224,7 +405,7 @@ func SBCReadCapacity(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
scb = cmd.SCB.Bytes()
|
||||
key = ILLEGAL_REQUEST
|
||||
asc = ASC_LUN_NOT_SUPPORTED
|
||||
data = cmd.InSDBBuffer.Buffer
|
||||
data = &bytes.Buffer{}
|
||||
bshift = cmd.Device.BlockShift
|
||||
size = cmd.Device.Size >> bshift
|
||||
)
|
||||
@@ -240,9 +421,11 @@ func SBCReadCapacity(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
goto sense
|
||||
}
|
||||
|
||||
if cmd.InSDBBuffer.Length < 8 {
|
||||
goto overflow
|
||||
}
|
||||
/*
|
||||
if cmd.InSDBBuffer.Length < 8 {
|
||||
goto overflow
|
||||
}
|
||||
*/
|
||||
|
||||
// data[0] = (size >> 32) ? __cpu_to_be32(0xffffffff) : __cpu_to_be32(size - 1);
|
||||
if size>>32 != 0 {
|
||||
@@ -253,8 +436,9 @@ func SBCReadCapacity(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
|
||||
// data[1] = __cpu_to_be32(1U << bshift);
|
||||
binary.Write(data, binary.BigEndian, uint32(1<<bshift))
|
||||
overflow:
|
||||
//overflow:
|
||||
cmd.InSDBBuffer.Resid = 8
|
||||
cmd.InSDBBuffer.Buffer = data
|
||||
return api.SAMStatGood
|
||||
sense:
|
||||
cmd.InSDBBuffer.Resid = 0
|
||||
@@ -293,6 +477,12 @@ sense:
|
||||
}
|
||||
|
||||
func SBCReadCapacity16(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
data := &bytes.Buffer{}
|
||||
data.Write(util.MarshalUint64(1))
|
||||
data.Write(util.MarshalUint32(1 << cmd.Device.BlockShift))
|
||||
val := (cmd.Device.Attrs.Lbppbe << 16) | cmd.Device.Attrs.LowestAlignedLBA
|
||||
data.Write(util.MarshalUint32(uint32(val)))
|
||||
cmd.InSDBBuffer.Buffer = data
|
||||
return api.SAMStatGood
|
||||
}
|
||||
|
||||
@@ -301,6 +491,13 @@ func SBCGetLbaStatus(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
}
|
||||
|
||||
func SBCServiceAction(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
opcode := api.SCSICommandType(cmd.SCB.Bytes()[1] & 0x1f)
|
||||
switch opcode {
|
||||
case api.READ_CAPACITY:
|
||||
return SBCReadCapacity(host, cmd)
|
||||
case api.SAI_READ_CAPACITY_16:
|
||||
return SBCReadCapacity16(host, cmd)
|
||||
}
|
||||
return api.SAMStatGood
|
||||
}
|
||||
|
||||
|
||||
+114
-13
@@ -16,17 +16,82 @@ limitations under the License.
|
||||
|
||||
package scsi
|
||||
|
||||
import "github.com/gostor/gotgt/pkg/api"
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
type CommandFunc func(host int, cmd *api.SCSICommand) api.SAMStat
|
||||
"github.com/golang/glog"
|
||||
"github.com/gostor/gotgt/pkg/api"
|
||||
)
|
||||
|
||||
type SCSITargetService struct {
|
||||
mutex sync.RWMutex
|
||||
Targets []*api.SCSITarget
|
||||
}
|
||||
|
||||
var _instance *SCSITargetService
|
||||
|
||||
func NewSCSITargetService() *SCSITargetService {
|
||||
if _instance == nil {
|
||||
_instance = &SCSITargetService{Targets: []*api.SCSITarget{}}
|
||||
}
|
||||
return _instance
|
||||
}
|
||||
|
||||
func (s *SCSITargetService) GetTargetList() ([]api.SCSITarget, error) {
|
||||
result := []api.SCSITarget{}
|
||||
s.mutex.RLock()
|
||||
for _, t := range s.Targets {
|
||||
result = append(result, *t)
|
||||
}
|
||||
s.mutex.RUnlock()
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *SCSITargetService) AddCommandQueue(tid int, scmd *api.SCSICommand) error {
|
||||
var (
|
||||
target *api.SCSITarget
|
||||
itn *api.ITNexus
|
||||
)
|
||||
s.mutex.RLock()
|
||||
for _, t := range s.Targets {
|
||||
if t.TID == tid {
|
||||
target = t
|
||||
break
|
||||
}
|
||||
}
|
||||
s.mutex.RUnlock()
|
||||
if target == nil {
|
||||
return fmt.Errorf("Cannot find the target with ID(%d)", tid)
|
||||
}
|
||||
scmd.Target = target
|
||||
for _, it := range target.ITNexus {
|
||||
if it.ID == scmd.CommandITNID {
|
||||
itn = it
|
||||
break
|
||||
}
|
||||
}
|
||||
scmd.ITNexus = itn
|
||||
|
||||
scmd.Device = target.Devices[0]
|
||||
result := scmd.Device.PerformCommand(tid, scmd)
|
||||
scmd.Result = result.Stat
|
||||
if result.Err != nil {
|
||||
glog.Error(result.Err)
|
||||
return result.Err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type SCSIServiceAction struct {
|
||||
ServiceAction uint32
|
||||
CommandPerformFunc CommandFunc
|
||||
CommandPerformFunc api.CommandFunc
|
||||
}
|
||||
|
||||
type SCSIDeviceOperation struct {
|
||||
CommandPerformFunc CommandFunc
|
||||
CommandPerformFunc api.CommandFunc
|
||||
ServiceAction *SCSIServiceAction
|
||||
PRConflictBits uint8
|
||||
}
|
||||
@@ -36,15 +101,7 @@ type BaseSCSIDeviceProtocol struct {
|
||||
SCSIDeviceOps []SCSIDeviceOperation
|
||||
}
|
||||
|
||||
type SCSIDeviceProtocol interface {
|
||||
InitLu(lu *api.SCSILu) error
|
||||
ExitLu(lu *api.SCSILu) error
|
||||
ConfigLu(lu *api.SCSILu) error
|
||||
OnlineLu(lu *api.SCSILu) error
|
||||
OfflineLu(lu *api.SCSILu) error
|
||||
}
|
||||
|
||||
func NewSCSIDeviceOperation(fn CommandFunc, sa *SCSIServiceAction, pr uint8) SCSIDeviceOperation {
|
||||
func NewSCSIDeviceOperation(fn api.CommandFunc, sa *SCSIServiceAction, pr uint8) SCSIDeviceOperation {
|
||||
return SCSIDeviceOperation{
|
||||
CommandPerformFunc: fn,
|
||||
ServiceAction: sa,
|
||||
@@ -54,6 +111,9 @@ func NewSCSIDeviceOperation(fn CommandFunc, sa *SCSIServiceAction, pr uint8) SCS
|
||||
|
||||
func BuildSenseData(cmd *api.SCSICommand, key byte, asc SCSISubError) {
|
||||
senseBuffer := cmd.SenseBuffer
|
||||
if senseBuffer == nil {
|
||||
senseBuffer = &bytes.Buffer{}
|
||||
}
|
||||
if cmd.Device.Attrs.SenseFormat {
|
||||
// descriptor format
|
||||
// current, not deferred
|
||||
@@ -81,3 +141,44 @@ func BuildSenseData(cmd *api.SCSICommand, key byte, asc SCSISubError) {
|
||||
cmd.SenseLength = length + 8
|
||||
}
|
||||
}
|
||||
|
||||
func getSCSIReadWriteOffset(scb []byte) uint64 {
|
||||
var off uint64
|
||||
var opcode = api.SCSICommandType(scb[0])
|
||||
|
||||
switch opcode {
|
||||
case api.READ_6, api.WRITE_6:
|
||||
off = uint64((scb[1]&0x1f))<<16 + uint64(scb[2])<<8 + uint64(scb[3])
|
||||
case api.READ_10, api.PRE_FETCH_10, api.WRITE_10, api.VERIFY_10, api.WRITE_VERIFY, api.WRITE_SAME, api.SYNCHRONIZE_CACHE, api.READ_12, api.WRITE_12, api.VERIFY_12, api.WRITE_VERIFY_12:
|
||||
off = uint64(binary.BigEndian.Uint32(scb[2:]))
|
||||
case api.READ_16, api.PRE_FETCH_16, api.WRITE_16, api.ORWRITE_16, api.VERIFY_16, api.WRITE_VERIFY_16, api.WRITE_SAME_16, api.SYNCHRONIZE_CACHE_16, api.COMPARE_AND_WRITE:
|
||||
off = binary.BigEndian.Uint64(scb[2:])
|
||||
default:
|
||||
}
|
||||
|
||||
return off
|
||||
}
|
||||
|
||||
func getSCSIReadWriteCount(scb []byte) uint32 {
|
||||
var cnt uint32
|
||||
var opcode = api.SCSICommandType(scb[0])
|
||||
|
||||
switch opcode {
|
||||
case api.READ_6, api.WRITE_6:
|
||||
cnt = uint32(scb[4])
|
||||
if cnt == 0 {
|
||||
cnt = 256
|
||||
}
|
||||
case api.READ_10, api.PRE_FETCH_10, api.WRITE_10, api.VERIFY_10, api.WRITE_VERIFY, api.WRITE_SAME, api.SYNCHRONIZE_CACHE:
|
||||
cnt = uint32(scb[7])<<8 | uint32(scb[8])
|
||||
case api.READ_12, api.WRITE_12, api.VERIFY_12, api.WRITE_VERIFY_12:
|
||||
cnt = binary.BigEndian.Uint32(scb[6:])
|
||||
case api.READ_16, api.PRE_FETCH_16, api.WRITE_16, api.ORWRITE_16, api.VERIFY_16, api.WRITE_VERIFY_16, api.WRITE_SAME_16, api.SYNCHRONIZE_CACHE_16:
|
||||
cnt = binary.BigEndian.Uint32(scb[10:])
|
||||
case api.COMPARE_AND_WRITE:
|
||||
cnt = uint32(scb[13])
|
||||
default:
|
||||
}
|
||||
|
||||
return cnt
|
||||
}
|
||||
|
||||
+160
-12
@@ -21,7 +21,9 @@ import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/gostor/gotgt/pkg/api"
|
||||
"github.com/gostor/gotgt/pkg/util"
|
||||
)
|
||||
@@ -128,6 +130,39 @@ func SPCLuOnline(lu *api.SCSILu) error {
|
||||
}
|
||||
|
||||
func SPCInquiry(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
buf := &bytes.Buffer{}
|
||||
var b byte = 0x75
|
||||
if reflect.DeepEqual(util.MarshalUint64(cmd.Device.Lun)[0:7], cmd.Lun[0:7]) {
|
||||
b = (uint8(0) & 0x7) << 5
|
||||
b |= uint8(0) & 0x1f
|
||||
}
|
||||
buf.WriteByte(b)
|
||||
b = 0
|
||||
buf.WriteByte(b)
|
||||
buf.WriteByte(byte(1))
|
||||
b = 0x02
|
||||
buf.WriteByte(b)
|
||||
buf.WriteByte(0x00)
|
||||
// byte 5
|
||||
b = 0
|
||||
b |= byte(1) << 4 & 0x30
|
||||
buf.WriteByte(b)
|
||||
// byte 6
|
||||
b = 0
|
||||
buf.WriteByte(b)
|
||||
buf.WriteByte(0x02)
|
||||
buf.Write([]byte{'1', '1', 'c', 'a', 'n', 's'})
|
||||
buf.WriteByte(0x00)
|
||||
buf.WriteByte(0x00)
|
||||
buf.Write([]byte{'c', 'o', 'f', 'f', 'e', 'e'})
|
||||
for i := 0; i < 10; i++ {
|
||||
buf.WriteByte(0x00)
|
||||
}
|
||||
buf.Write([]byte{'1', '.', '0'})
|
||||
buf.WriteByte(0x00)
|
||||
data := buf.Bytes()
|
||||
data[4] = byte(len(data) - 4)
|
||||
cmd.InSDBBuffer.Buffer = bytes.NewBuffer(data)
|
||||
return api.SAMStatGood
|
||||
}
|
||||
|
||||
@@ -137,25 +172,22 @@ func SPCReportLuns(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
actualLength uint32 = 8
|
||||
availLength uint32 = 0
|
||||
allocationLength uint32
|
||||
data *bytes.Buffer
|
||||
buf *bytes.Buffer = &bytes.Buffer{}
|
||||
scb *bytes.Buffer = cmd.SCB
|
||||
)
|
||||
// Get Allocation Length
|
||||
allocationLength = util.GetUnalignedUint32(scb.Bytes()[6:10])
|
||||
if allocationLength < 16 {
|
||||
glog.Warningf("goto sense, allocationLength < 16")
|
||||
goto sense
|
||||
}
|
||||
if cmd.InSDBBuffer.Length < allocationLength {
|
||||
goto sense
|
||||
}
|
||||
data = cmd.InSDBBuffer.Buffer
|
||||
remainLength = allocationLength - 8
|
||||
availLength = 8 * uint32(len(cmd.Target.Devices))
|
||||
binary.Write(data, binary.BigEndian, availLength)
|
||||
buf.Write(util.MarshalUint32(availLength))
|
||||
cmd.InSDBBuffer.Resid = int32(actualLength)
|
||||
// Skip through to byte 8, Reserved
|
||||
for i := 0; i < 4; i++ {
|
||||
data.WriteByte(0x00)
|
||||
buf.WriteByte(0x00)
|
||||
}
|
||||
|
||||
for _, lu := range cmd.Target.Devices {
|
||||
@@ -168,10 +200,11 @@ func SPCReportLuns(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
}
|
||||
lun = (0x3fff & lun) << 16
|
||||
lun = uint64(lun << 32)
|
||||
binary.Write(data, binary.BigEndian, lun)
|
||||
buf.Write(util.MarshalUint64(lun))
|
||||
remainLength -= 8
|
||||
}
|
||||
}
|
||||
cmd.InSDBBuffer.Buffer = buf
|
||||
return api.SAMStatGood
|
||||
sense:
|
||||
cmd.InSDBBuffer.Resid = 0
|
||||
@@ -218,9 +251,11 @@ func SPCStartStop(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
}
|
||||
|
||||
func SPCTestUnit(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
if err := deviceReserve(cmd); err != nil {
|
||||
return api.SAMStatReservationConflict
|
||||
}
|
||||
/*
|
||||
if err := deviceReserve(cmd); err != nil {
|
||||
return api.SAMStatReservationConflict
|
||||
}
|
||||
*/
|
||||
if cmd.Device.Attrs.Online {
|
||||
return api.SAMStatGood
|
||||
}
|
||||
@@ -247,7 +282,33 @@ func SPCPreventAllowMediaRemoval(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
// 6.11 - MODE SENSE(6)
|
||||
// 6.12 - MODE SENSE(10)
|
||||
func SPCModeSense(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
var (
|
||||
scb = cmd.SCB.Bytes()
|
||||
mode6 = (scb[0] == 0x1a)
|
||||
dbd = scb[1] & 0x8 /* Disable Block Descriptors */
|
||||
pcode = scb[2] & 0x3f
|
||||
pctrl = (scb[2] & 0xc0) >> 6
|
||||
subpcode = scb[3]
|
||||
blkDesctionLen = 0
|
||||
key = ILLEGAL_REQUEST
|
||||
asc = ASC_INVALID_FIELD_IN_CDB
|
||||
)
|
||||
if dbd == 0 {
|
||||
blkDesctionLen = 8
|
||||
}
|
||||
if pctrl == 3 {
|
||||
asc = ASC_SAVING_PARMS_UNSUP
|
||||
goto sense
|
||||
}
|
||||
_ = dbd
|
||||
_ = pcode
|
||||
_ = subpcode
|
||||
_ = mode6
|
||||
_ = blkDesctionLen
|
||||
return api.SAMStatGood
|
||||
sense:
|
||||
BuildSenseData(cmd, key, asc)
|
||||
return api.SAMStatCheckCondition
|
||||
}
|
||||
|
||||
func SPCSendDiagnostics(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
@@ -263,10 +324,93 @@ sense:
|
||||
return api.SAMStatCheckCondition
|
||||
}
|
||||
|
||||
func getSCSICmdSize(opcode api.SCSICommandType) byte {
|
||||
var scsi_command_size = []byte{6, 10, 10, 12, 16, 12, 10, 10}
|
||||
|
||||
return scsi_command_size[(byte(opcode)>>5)&7]
|
||||
}
|
||||
|
||||
func reportOpcodesAll(cmd *api.SCSICommand, rctd int) error {
|
||||
var (
|
||||
data = []byte{0x00, 0x00, 0x00, 0x00}
|
||||
)
|
||||
for _, i := range []api.SCSICommandType{api.TEST_UNIT_READY, api.WRITE_6, api.INQUIRY, api.READ_CAPACITY, api.WRITE_10, api.WRITE_16, api.REPORT_LUNS, api.WRITE_12} {
|
||||
data = append(data, byte(i))
|
||||
// reserved
|
||||
data = append(data, 0x00)
|
||||
// service action
|
||||
data = append(data, 0x00)
|
||||
data = append(data, 0x00)
|
||||
// reserved
|
||||
data = append(data, 0x00)
|
||||
// flags : no service action, possibly timeout desc
|
||||
if rctd != 0 {
|
||||
data = append(data, 0x02)
|
||||
} else {
|
||||
data = append(data, 0x00)
|
||||
}
|
||||
// cdb length
|
||||
length := getSCSICmdSize(i)
|
||||
data = append(data, (length>>8)&0xff)
|
||||
data = append(data, length&0xff)
|
||||
// timeout descriptor
|
||||
if rctd != 0 {
|
||||
// length == 0x0a
|
||||
data[1] = 0x0a
|
||||
for n := 0; n < 12; n++ {
|
||||
data = append(data, 0x00)
|
||||
}
|
||||
}
|
||||
}
|
||||
buf := util.MarshalUint32(uint32(len(data) - 4))
|
||||
buf = append(buf, data[4:]...)
|
||||
cmd.InSDBBuffer.Buffer = bytes.NewBuffer(buf)
|
||||
return nil
|
||||
}
|
||||
|
||||
func reportOpcodeOne(cmd *api.SCSICommand, rctd int, opcode byte, rsa uint16, serviceAction bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// This is useful for the various commands using the SERVICE ACTION format.
|
||||
func SPCServiceAction(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
// TODO
|
||||
scb := cmd.SCB.Bytes()
|
||||
reporting_options := scb[2] & 0x07
|
||||
opcode := scb[3]
|
||||
rctd := int(scb[2] & 0x80)
|
||||
rsa := util.GetUnalignedUint16(scb[4:])
|
||||
switch reporting_options {
|
||||
case 0x00: /* report all */
|
||||
glog.V(3).Infof("Service Action: report all")
|
||||
err := reportOpcodesAll(cmd, rctd)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
goto sense
|
||||
}
|
||||
case 0x01: /* report one no service action*/
|
||||
glog.V(3).Infof("Service Action: report one no service action")
|
||||
err := reportOpcodeOne(cmd, rctd, opcode, rsa, false)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
goto sense
|
||||
}
|
||||
case 0x02: /* report one service action */
|
||||
glog.V(3).Infof("Service Action: report one service action")
|
||||
err := reportOpcodeOne(cmd, rctd, opcode, rsa, true)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
goto sense
|
||||
}
|
||||
default:
|
||||
goto sense
|
||||
}
|
||||
return api.SAMStatGood
|
||||
|
||||
sense:
|
||||
cmd.InSDBBuffer.Resid = 0
|
||||
BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB)
|
||||
return api.SAMStatCheckCondition
|
||||
}
|
||||
|
||||
func SPCPRReadKeys(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
@@ -360,6 +504,7 @@ func SPCRequestSense(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
var (
|
||||
allocationLength uint32
|
||||
actualLength uint32
|
||||
data = &bytes.Buffer{}
|
||||
)
|
||||
|
||||
allocationLength = util.GetUnalignedUint32(cmd.SCB.Bytes()[4:8])
|
||||
@@ -372,8 +517,11 @@ func SPCRequestSense(host int, cmd *api.SCSICommand) api.SAMStat {
|
||||
} else {
|
||||
actualLength = allocationLength
|
||||
}
|
||||
binary.Write(cmd.InSDBBuffer.Buffer, binary.BigEndian, cmd.SenseBuffer.Bytes()[0:actualLength])
|
||||
if cmd.SenseBuffer != nil {
|
||||
data.Write(cmd.SenseBuffer.Bytes()[0:actualLength])
|
||||
}
|
||||
cmd.InSDBBuffer.Resid = int32(actualLength)
|
||||
cmd.InSDBBuffer.Buffer = data
|
||||
|
||||
// reset sense buffer in cmnd
|
||||
cmd.SenseBuffer = &bytes.Buffer{}
|
||||
|
||||
+16
-6
@@ -21,18 +21,28 @@ import (
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/gostor/gotgt/pkg/api"
|
||||
"github.com/gostor/gotgt/pkg/port"
|
||||
)
|
||||
|
||||
func NewTarget(tid int, driverName, name 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}
|
||||
var tgt = port.NewTargetDriver(driverName, target)
|
||||
target.SCSITargetDriver = tgt
|
||||
var target = &api.SCSITarget{
|
||||
Name: name,
|
||||
TID: tid,
|
||||
Devices: []*api.SCSILu{},
|
||||
}
|
||||
lun, err := NewSCSILu(0, target)
|
||||
if err != nil {
|
||||
glog.Errorf("fail to create LU: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
s.mutex.Lock()
|
||||
target.Devices = append(target.Devices, lun)
|
||||
s.Targets = append(s.Targets, target)
|
||||
s.mutex.Unlock()
|
||||
return target, nil
|
||||
}
|
||||
|
||||
@@ -40,7 +50,7 @@ func deviceReserve(cmd *api.SCSICommand) error {
|
||||
var lu *api.SCSILu
|
||||
for _, dev := range cmd.Target.Devices {
|
||||
if dev.Lun == cmd.Device.Lun {
|
||||
lu = &dev
|
||||
lu = dev
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user