diff --git a/pkg/api/types.go b/pkg/api/types.go index 9b533a0..5cfd965 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -19,7 +19,7 @@ import ( "errors" "sync" - "github.com/satori/go.uuid" + uuid "github.com/satori/go.uuid" ) type SCSICommandType byte @@ -351,6 +351,7 @@ type BackingStore interface { Write([]byte, int64) error DataSync() error DataAdvise(int64, int64, uint32) error + Unmap() error } type SCSIDeviceProtocol interface { diff --git a/pkg/config/config.go b/pkg/config/config.go index 092b81f..8aa95b9 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -101,9 +101,11 @@ var ( ) type BackendStorage struct { - DeviceID uint64 `json:"deviceID"` - Path string `json:"path"` - Online bool `json:"online"` + DeviceID uint64 `json:"deviceID"` + Path string `json:"path"` + Online bool `json:"online"` + Thinprovisioning bool `json:"thinprovisioning"` + BlockShift uint `json:"blockShift"` } type ISCSIPortalInfo struct { diff --git a/pkg/scsi/backingstore.go b/pkg/scsi/backingstore.go index 7cf0315..6dcb541 100644 --- a/pkg/scsi/backingstore.go +++ b/pkg/scsi/backingstore.go @@ -135,7 +135,11 @@ func bsPerformCommand(bs api.BackingStore, cmd *api.SCSICommand) (err error, key doVerify = true goto verify case api.UNMAP: - // TODO + err = bs.Unmap() + if err != nil { + key = MEDIUM_ERROR + asc = NO_ADDITIONAL_SENSE + } default: break } diff --git a/pkg/scsi/backingstore/cephstore_linux.go b/pkg/scsi/backingstore/cephstore_linux.go index 291283a..c77820a 100644 --- a/pkg/scsi/backingstore/cephstore_linux.go +++ b/pkg/scsi/backingstore/cephstore_linux.go @@ -149,3 +149,7 @@ func (bs *CephBackingStore) DataSync() error { func (bs *CephBackingStore) DataAdvise(offset, length int64, advise uint32) error { return nil } + +func (bs *CephBackingStore) Unmap() error { + return nil +} diff --git a/pkg/scsi/backingstore/common.go b/pkg/scsi/backingstore/common.go index 4d78fab..fc35bad 100644 --- a/pkg/scsi/backingstore/common.go +++ b/pkg/scsi/backingstore/common.go @@ -113,3 +113,7 @@ func (bs *FileBackingStore) DataSync() error { func (bs *FileBackingStore) DataAdvise(offset, length int64, advise uint32) error { return util.Fadvise(bs.file, offset, length, advise) } + +func (bs *FileBackingStore) Unmap() error { + return nil +} diff --git a/pkg/scsi/backingstore/null.go b/pkg/scsi/backingstore/null.go index 2cbde02..f718d9a 100644 --- a/pkg/scsi/backingstore/null.go +++ b/pkg/scsi/backingstore/null.go @@ -74,3 +74,7 @@ func (bs *NullBackingStore) DataSync() error { func (bs *NullBackingStore) DataAdvise(offset, length int64, advise uint32) error { return nil } + +func (bs *NullBackingStore) Unmap() error { + return nil +} diff --git a/pkg/scsi/lun.go b/pkg/scsi/lun.go index a7a8afa..790377d 100644 --- a/pkg/scsi/lun.go +++ b/pkg/scsi/lun.go @@ -20,13 +20,13 @@ import ( "strings" "github.com/gostor/gotgt/pkg/api" + "github.com/gostor/gotgt/pkg/config" ) // NewSCSILu: create a new SCSI LU // path format :/absolute/file/path -func NewSCSILu(device_uuid uint64, path string, online bool) (*api.SCSILu, error) { - - pathinfo := strings.SplitN(path, ":", 2) +func NewSCSILu(bs *config.BackendStorage) (*api.SCSILu, error) { + pathinfo := strings.SplitN(bs.Path, ":", 2) if len(pathinfo) < 2 { return nil, errors.New("invalid device path string") } @@ -43,8 +43,8 @@ func NewSCSILu(device_uuid uint64, path string, online bool) (*api.SCSILu, error PerformCommand: luPerformCommand, DeviceProtocol: sbc, Storage: backing, - BlockShift: api.DefaultBlockShift, - UUID: device_uuid, + BlockShift: bs.BlockShift, + UUID: bs.DeviceID, } err = backing.Open(lu, backendPath) @@ -53,7 +53,8 @@ func NewSCSILu(device_uuid uint64, path string, online bool) (*api.SCSILu, error } lu.Size = backing.Size(lu) lu.DeviceProtocol.InitLu(lu) - lu.Attrs.Online = online + lu.Attrs.Thinprovisioning = bs.Thinprovisioning + lu.Attrs.Online = bs.Online lu.Attrs.Lbppbe = 3 return lu, nil } diff --git a/pkg/scsi/sbc.go b/pkg/scsi/sbc.go index ad54aec..36e668e 100644 --- a/pkg/scsi/sbc.go +++ b/pkg/scsi/sbc.go @@ -295,7 +295,13 @@ sense: } func SBCUnmap(host int, cmd *api.SCSICommand) api.SAMStat { - return api.SAMStatGood + err, key, asc := bsPerformCommand(cmd.Device.Storage, cmd) + if err == nil { + return api.SAMStatGood + } + + BuildSenseData(cmd, key, asc) + return api.SAMStatCheckCondition } /* @@ -594,7 +600,11 @@ func SBCReadCapacity16(host int, cmd *api.SCSICommand) api.SAMStat { if allocationLength > 12 { copy(cmd.InSDBBuffer.Buffer[8:], util.MarshalUint32(uint32(1< 16 { - val := (cmd.Device.Attrs.Lbppbe << 16) | cmd.Device.Attrs.LowestAlignedLBA + var lbpme int + if cmd.Device.Attrs.Thinprovisioning { + lbpme = 1 + } + val := (cmd.Device.Attrs.Lbppbe << 16) | (lbpme << 15) | cmd.Device.Attrs.LowestAlignedLBA copy(cmd.InSDBBuffer.Buffer[12:], util.MarshalUint32(uint32(val))) } } diff --git a/pkg/scsi/scsilumap.go b/pkg/scsi/scsilumap.go index 5803507..a968eef 100644 --- a/pkg/scsi/scsilumap.go +++ b/pkg/scsi/scsilumap.go @@ -73,7 +73,7 @@ func InitSCSILUMap(config *config.Config) error { defer globalSCSILUMap.mutex.Unlock() for _, bs := range config.Storages { - lu, err := NewSCSILu(bs.DeviceID, bs.Path, bs.Online) + lu, err := NewSCSILu(&bs) if err != nil { return fmt.Errorf("Init SCSI LU map error: %v", err) } diff --git a/pkg/scsi/spc.go b/pkg/scsi/spc.go index cc1bc7e..41b403c 100644 --- a/pkg/scsi/spc.go +++ b/pkg/scsi/spc.go @@ -25,7 +25,7 @@ import ( log "github.com/Sirupsen/logrus" "github.com/gostor/gotgt/pkg/api" "github.com/gostor/gotgt/pkg/util" - "github.com/satori/go.uuid" + uuid "github.com/satori/go.uuid" ) func SPCIllegalOp(host int, cmd *api.SCSICommand) api.SAMStat { @@ -58,6 +58,7 @@ func InquiryPage0x00(host int, cmd *api.SCSICommand) (*bytes.Buffer, uint16) { descBuf.WriteByte(0x00) descBuf.WriteByte(0x80) descBuf.WriteByte(0x83) + descBuf.WriteByte(0xB0) /* TODO: descBuf.WriteByte(0x86) @@ -188,6 +189,42 @@ func InquiryPage0x83(host int, cmd *api.SCSICommand) (*bytes.Buffer, uint16) { return buf, pageLength } +func InquiryPage0xB0(host int, cmd *api.SCSICommand) (*bytes.Buffer, uint16) { + var ( + buf = &bytes.Buffer{} + pageLength uint16 = 0x3C + maxUnmapLbaCount uint32 = 0 + maxUnmapBlockDescriptorCount uint32 = 0 + ) + + if cmd.Device.Attrs.Thinprovisioning { + maxUnmapLbaCount = 0xFFFFFFFF + maxUnmapBlockDescriptorCount = 0xFFFFFFFF + } + + //byte 0 + if cmd.Device.Attrs.Online { + buf.WriteByte(PQ_DEVICE_CONNECTED | byte(cmd.Device.Attrs.DeviceType)) + } else { + buf.WriteByte(PQ_DEVICE_NOT_CONNECT | byte(cmd.Device.Attrs.DeviceType)) + } + //PAGE CODE + buf.WriteByte(0xB0) + //PAGE LENGTH + binary.Write(buf, binary.BigEndian, pageLength) + + buf.Write(make([]byte, 16)) + + //MAXIMUM UNMAP LBA COUNT + binary.Write(buf, binary.BigEndian, maxUnmapLbaCount) + + //MAXIMUM UNMAP BLOCK DESCRIPTOR COUNT + binary.Write(buf, binary.BigEndian, maxUnmapBlockDescriptorCount) + + buf.Write(make([]byte, 36)) + return buf, pageLength +} + /* * SPCInquiry Implements SCSI INQUIRY command * The INQUIRY command requests the device server to return information regarding the logical unit and SCSI target device. @@ -231,6 +268,8 @@ func SPCInquiry(host int, cmd *api.SCSICommand) api.SAMStat { buf, _ = InquiryPage0x80(host, cmd) case 0x83: buf, _ = InquiryPage0x83(host, cmd) + case 0xB0: + buf, _ = InquiryPage0xB0(host, cmd) default: goto sense } @@ -610,7 +649,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} { + 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, api.UNMAP} { data = append(data, byte(i)) // reserved data = append(data, 0x00) @@ -627,7 +666,7 @@ func reportOpcodesAll(cmd *api.SCSICommand, rctd int) error { } // cdb length length := getSCSICmdSize(i) - data = append(data, (length>>8)&0xff) + data = append(data, 0) data = append(data, length&0xff) // timeout descriptor if rctd != 0 {