From d770eb33ac7370dcefc81a9cdb77ea16c90fa78c Mon Sep 17 00:00:00 2001 From: Lei Xue Date: Sun, 27 Dec 2015 20:44:54 +0800 Subject: [PATCH 1/3] init commit for spc/sbc --- pkg/scsi/cmd.go | 34 +++--- pkg/scsi/drivers.go | 2 +- pkg/scsi/error.go | 49 +++++--- pkg/scsi/lun.go | 64 ++++++++-- pkg/scsi/sbc.go | 208 +++++++++++++++++++++++++++----- pkg/scsi/sbc_test.go | 56 +++++++++ pkg/scsi/scsi.go | 76 ++++++++++-- pkg/scsi/spc.go | 277 +++++++++++++++++++++++++++++++++++++------ pkg/scsi/spc_test.go | 73 ++++++++++++ pkg/scsi/target.go | 59 ++++++++- pkg/util/util.go | 14 +++ 11 files changed, 788 insertions(+), 124 deletions(-) create mode 100644 pkg/scsi/sbc_test.go create mode 100644 pkg/scsi/spc_test.go diff --git a/pkg/scsi/cmd.go b/pkg/scsi/cmd.go index 1d22add..0c80d5d 100644 --- a/pkg/scsi/cmd.go +++ b/pkg/scsi/cmd.go @@ -16,6 +16,8 @@ limitations under the License. package scsi +import "bytes" + type SCSICommandType byte var ( @@ -185,8 +187,8 @@ const ( ) type SCSIDataBuffer struct { - Buffer uint64 - Length uint64 + Buffer *bytes.Buffer + Length uint32 TransferLength uint32 Resid int32 } @@ -197,20 +199,22 @@ type SCSICommand struct { Device *SCSILu State uint64 Direction SCSIDataDirection - InSDBBuffer *SCSIDataBuffer - OutSDBBuffer *SCSIDataBuffer + InSDBBuffer SCSIDataBuffer + OutSDBBuffer SCSIDataBuffer // Command ITN ID - CommandITNID uint64 - Offset uint64 - TL uint32 - SCB *[]byte - SCBLength int - Lun []uint8 - Attribute int - Tag uint64 - Result int - SenseBuffer []byte - SenseLength int + CommandITNID uint64 + Offset uint64 + TL uint32 + SCB *bytes.Buffer + SCBLength int + Lun []uint8 + Attribute int + Tag uint64 + Result int + SenseBuffer *bytes.Buffer + SenseLength uint32 + ITNexus *ITNexus + ITNexusLuInfo *ITNexusLuInfo } func SCSICDBGroupID(opcode byte) byte { diff --git a/pkg/scsi/drivers.go b/pkg/scsi/drivers.go index 595d674..61c2428 100644 --- a/pkg/scsi/drivers.go +++ b/pkg/scsi/drivers.go @@ -47,7 +47,7 @@ type SCSITargetDriverOps interface { DestroyPortal(name string) error CreateLu(lu *SCSILu) error - GetLun(lun uint8) (uint64, error) + GetLu(lun uint8) (uint64, error) CommandNotify(nid uint64, result int, cmd *SCSICommand) error } diff --git a/pkg/scsi/error.go b/pkg/scsi/error.go index a2b10af..e2b4d70 100644 --- a/pkg/scsi/error.go +++ b/pkg/scsi/error.go @@ -16,22 +16,43 @@ limitations under the License. package scsi -type SCSIError byte +import "errors" + +type SCSIError struct { + errno byte + Err error +} var ( - NO_SENSE SCSIError = 0x00 - RECOVERED_ERROR SCSIError = 0x01 - NOT_READY SCSIError = 0x02 - MEDIUM_ERROR SCSIError = 0x03 - HARDWARE_ERROR SCSIError = 0x04 - ILLEGAL_REQUEST SCSIError = 0x05 - UNIT_ATTENTION SCSIError = 0x06 - DATA_PROTECT SCSIError = 0x07 - BLANK_CHECK SCSIError = 0x08 - COPY_ABORTED SCSIError = 0x0a - ABORTED_COMMAND SCSIError = 0x0b - VOLUME_OVERFLOW SCSIError = 0x0d - MISCOMPARE SCSIError = 0x0e + NO_SENSE byte = 0x00 + RECOVERED_ERROR byte = 0x01 + NOT_READY byte = 0x02 + MEDIUM_ERROR byte = 0x03 + HARDWARE_ERROR byte = 0x04 + ILLEGAL_REQUEST byte = 0x05 + UNIT_ATTENTION byte = 0x06 + DATA_PROTECT byte = 0x07 + BLANK_CHECK byte = 0x08 + COPY_ABORTED byte = 0x0a + ABORTED_COMMAND byte = 0x0b + VOLUME_OVERFLOW byte = 0x0d + MISCOMPARE byte = 0x0e +) + +var ( + NoSenseError = SCSIError{NO_SENSE, errors.New("no sense")} + RecoveredError = SCSIError{RECOVERED_ERROR, errors.New("recovered error")} + NotReadyError = SCSIError{NOT_READY, errors.New("not ready")} + MediumError = SCSIError{MEDIUM_ERROR, errors.New("medium error")} + HardwareError = SCSIError{HARDWARE_ERROR, errors.New("hardware error")} + IllegalRequestError = SCSIError{ILLEGAL_REQUEST, errors.New("illegal request")} + UnitAttentionError = SCSIError{UNIT_ATTENTION, errors.New("unit attention")} + DataProtectError = SCSIError{DATA_PROTECT, errors.New("data protect")} + BlankCheckError = SCSIError{BLANK_CHECK, errors.New("blank check")} + CopyAbortedError = SCSIError{COPY_ABORTED, errors.New("copy aborted")} + AbortedCommandError = SCSIError{ABORTED_COMMAND, errors.New("aborted command")} + VolumeOverflowError = SCSIError{VOLUME_OVERFLOW, errors.New("volume overflow")} + MiscompareError = SCSIError{MISCOMPARE, errors.New("miscompare")} ) type SCSISubError uint16 diff --git a/pkg/scsi/lun.go b/pkg/scsi/lun.go index d85dfe8..ce6724b 100644 --- a/pkg/scsi/lun.go +++ b/pkg/scsi/lun.go @@ -16,14 +16,58 @@ limitations under the License. package scsi -type SCSILu struct { - FD int - Address uint64 - Size uint64 - Lun uint64 - Path string - BsoFlags int - BlockShift uint - ReserveID uint64 - Target *SCSITarget +type SCSILuPhyAttribute struct { + SCSIID string + SCSISN string + NumID uint64 + VendorID string + ProductID string + ProductRev string + VersionDesction []uint16 + // Peripheral device type + DeviceType uint + // Peripheral Qualifier + Qualifier bool + // Removable media + Removable bool + // Read Only media + Readonly bool + // Software Write Protect + SWP bool + // Use thin-provisioning for this LUN + Thinprovisioning bool + // Logical Unit online + Online bool + // Descrptor format sense data supported + SenseFormat bool + // Logical blocks per physical block exponent + Lbppbe int + // Do not update it automatically when the backing file changes + NoLbppbe int + // Lowest aligned LBA + LowestAlignedLBA int +} + +type SCSILu struct { + FD int + Address uint64 + Size uint64 + Lun uint64 + Path string + BsoFlags int + BlockShift uint + ReserveID uint64 + DeviceProtocol SCSIDeviceProtocol + Storage *BackingStore + Target *SCSITarget + Attrs SCSILuPhyAttribute + + // function handler for command performing and finishing + PerformCommand CommandFunc + FinishCommand func(*SCSITarget, *SCSICommand) +} + +func luPreventRemoval(lu *SCSILu) bool { + // TODO + return false } diff --git a/pkg/scsi/sbc.go b/pkg/scsi/sbc.go index 3e75230..721244f 100644 --- a/pkg/scsi/sbc.go +++ b/pkg/scsi/sbc.go @@ -17,6 +17,8 @@ limitations under the License. // SCSI block command processing package scsi +import "encoding/binary" + type SBCSCSIDeviceProtocol struct { BaseSCSIDeviceProtocol } @@ -37,10 +39,12 @@ func (sbc *SBCSCSIDeviceProtocol) OfflineLu(lu *SCSILu) error { return nil } -func NewSBCDevice() (SBCSCSIDeviceProtocol, error) { +func NewSBCDevice() SBCSCSIDeviceProtocol { var sbc = SBCSCSIDeviceProtocol{ - BaseSCSIDeviceProtocol{Type: TYPE_DISK, - SCSIDeviceOps: make([]SCSIDeviceOperation, 256)}, + BaseSCSIDeviceProtocol{ + Type: TYPE_DISK, + SCSIDeviceOps: make([]SCSIDeviceOperation, 256), + }, } for i := 0; i <= 256; i++ { sbc.SCSIDeviceOps = append(sbc.SCSIDeviceOps, NewSCSIDeviceOperation(SPCIllegalOp, nil, 0)) @@ -95,57 +99,201 @@ func NewSBCDevice() (SBCSCSIDeviceProtocol, error) { sbc.SCSIDeviceOps[WRITE_VERIFY_12] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN) sbc.SCSIDeviceOps[VERIFY_12] = NewSCSIDeviceOperation(SBCVerify, nil, PR_EA_FA|PR_EA_FN) - return sbc, nil + return sbc } -func SBCModeSelect(host int, cmd *SCSICommand) error { - return nil +func SBCModeSelect(host int, cmd *SCSICommand) SAMStat { + return SAMStatGood } -func SBCModeSense(host int, cmd *SCSICommand) error { - return nil +func SBCModeSense(host int, cmd *SCSICommand) SAMStat { + // DPOFUA = 0x10 + var deviceSpecific uint8 = 0x10 + + if err := SPCModeSense(host, cmd); err.Err != nil { + return err + } + + // If this is a read-only lun, we must set the write protect bit + if cmd.Device.Attrs.Readonly || cmd.Device.Attrs.SWP { + deviceSpecific |= 0x80 + } + + data := cmd.InSDBBuffer.Buffer + data.Next(2) + + if cmd.SCB.Bytes()[0] == 0x1a { + data.WriteByte(deviceSpecific) + } else { + data.Next(1) + data.WriteByte(deviceSpecific) + } + + return SAMStatGood } -func SBCFormatUnit(host int, cmd *SCSICommand) error { - return nil +// The FORMAT UNIT command requests that the device server format the medium into application client +// accessible logical blocks as specified in the number of blocks and block length values received +// in the last mode parameter block descriptor in a MODE SELECT command (see SPC-3). In addition, +// the device server may certify the medium and create control structures for the management of the medium and defects. +// The degree that the medium is altered by this command is vendor-specific. +func SBCFormatUnit(host int, cmd *SCSICommand) SAMStat { + var ( + key = ILLEGAL_REQUEST + asc = ASC_INVALID_FIELD_IN_CDB + ) + + if err := deviceReserve(cmd); err != nil { + return SAMStatReservationConflict + } + + if !cmd.Device.Attrs.Online { + key = NOT_READY + asc = ASC_MEDIUM_NOT_PRESENT + goto sense + } + + if cmd.Device.Attrs.Readonly || cmd.Device.Attrs.SWP { + key = DATA_PROTECT + asc = ASC_WRITE_PROTECT + goto sense + } + + if cmd.SCB.Bytes()[1]&0x80 != 0 { + // we dont support format protection information + goto sense + } + if cmd.SCB.Bytes()[1]&0x10 != 0 { + // we dont support format data + goto sense + } + if cmd.SCB.Bytes()[1]&0x07 != 0 { + // defect list format must be 0 + goto sense + } + + return SAMStatGood +sense: + BuildSenseData(cmd, key, asc) + return SAMStatCheckCondition } -func SBCUnmap(host int, cmd *SCSICommand) error { - return nil +func SBCUnmap(host int, cmd *SCSICommand) SAMStat { + return SAMStatGood } -func SBCReadWrite(host int, cmd *SCSICommand) error { - return nil +func SBCReadWrite(host int, cmd *SCSICommand) SAMStat { + return SAMStatGood } -func SBCReserve(host int, cmd *SCSICommand) error { - return nil +func SBCReserve(host int, cmd *SCSICommand) SAMStat { + if err := deviceReserve(cmd); err != nil { + return SAMStatReservationConflict + } + return SAMStatGood } -func SBCRelease(host int, cmd *SCSICommand) error { - return nil +func SBCRelease(host int, cmd *SCSICommand) SAMStat { + if err := deviceRelease(cmd.Target.TID, cmd.CommandITNID, cmd.Device.Lun, false); err != nil { + return SAMStatReservationConflict + } + + return SAMStatGood } -func SBCReadCapacity(host int, cmd *SCSICommand) error { - return nil +// The READ CAPACITY (10) command requests that the device server transfer 8 bytes of parameter data +// describing the capacity and medium format of the direct-access block device to the data-in buffer. +// This command may be processed as if it has a HEAD OF QUEUE task attribute. If the logical unit supports +// protection information, the application client should use the READ CAPACITY (16) command instead of +// the READ CAPACITY (10) command. +func SBCReadCapacity(host int, cmd *SCSICommand) SAMStat { + var ( + scb = cmd.SCB.Bytes() + key = ILLEGAL_REQUEST + asc = ASC_LUN_NOT_SUPPORTED + data = cmd.InSDBBuffer.Buffer + bshift = cmd.Device.BlockShift + size = cmd.Device.Size >> bshift + ) + + if cmd.Device.Attrs.Removable && !cmd.Device.Attrs.Online { + key = NOT_READY + asc = ASC_MEDIUM_NOT_PRESENT + goto sense + } + + if (scb[8]&0x1 == 0) && (scb[2]|scb[3]|scb[4]|scb[5]) != 0 { + asc = ASC_INVALID_FIELD_IN_CDB + goto sense + } + + if cmd.InSDBBuffer.Length < 8 { + goto overflow + } + + // data[0] = (size >> 32) ? __cpu_to_be32(0xffffffff) : __cpu_to_be32(size - 1); + if size>>32 != 0 { + binary.Write(data, binary.BigEndian, uint32(0xffffffff)) + } else { + binary.Write(data, binary.BigEndian, uint32(size-1)) + } + + // data[1] = __cpu_to_be32(1U << bshift); + binary.Write(data, binary.BigEndian, uint32(1<> 8) & 0xff) + senseBuffer.WriteByte(byte(asc) & 0xff) + cmd.SenseLength = 8 + } else { + // fixed format + var length uint32 = 0xa + // current, not deferred + senseBuffer.WriteByte(0x70) + senseBuffer.WriteByte(0x00) + senseBuffer.WriteByte(key) + for i := 0; i < 4; i++ { + senseBuffer.WriteByte(0x00) + } + senseBuffer.WriteByte(byte(length)) + for i := 0; i < 4; i++ { + senseBuffer.WriteByte(0x00) + } + senseBuffer.WriteByte((byte(asc) >> 8) & 0xff) + senseBuffer.WriteByte(byte(asc) & 0xff) + cmd.SenseLength = length + 8 + } +} diff --git a/pkg/scsi/spc.go b/pkg/scsi/spc.go index 9504bc2..7bcbb4c 100644 --- a/pkg/scsi/spc.go +++ b/pkg/scsi/spc.go @@ -17,6 +17,14 @@ limitations under the License. // SCSI primary command processing package scsi +import ( + "bytes" + "encoding/binary" + "fmt" + + "github.com/gostor/gotgt/pkg/util" +) + /* * Protocol Identifier Values * @@ -100,78 +108,275 @@ const ( DESG_SCSI ) -func SPCIllegalOp(host int, cmd *SCSICommand) error { +func SPCIllegalOp(host int, cmd *SCSICommand) SAMStat { + return SAMStatGood +} + +func SPCLuOffline(lu *SCSILu) error { + lu.Attrs.Online = true return nil } -func SPCInquiry(host int, cmd *SCSICommand) error { +func SPCLuOnline(lu *SCSILu) error { + if luPreventRemoval(lu) { + return fmt.Errorf("lu(%s) prevent removal", lu.Lun) + } + + lu.Attrs.Online = false return nil } -func SPCReportLuns(host int, cmd *SCSICommand) error { - return nil +func SPCInquiry(host int, cmd *SCSICommand) SAMStat { + return SAMStatGood } -func SPCStartStop(host int, cmd *SCSICommand) error { - return nil +func SPCReportLuns(host int, cmd *SCSICommand) SAMStat { + var ( + remainLength uint32 + actualLength uint32 = 8 + availLength uint32 = 0 + allocationLength uint32 + data *bytes.Buffer + scb *bytes.Buffer = cmd.SCB + ) + // Get Allocation Length + allocationLength = util.GetUnalignedUint32(scb.Bytes()[6:10]) + if 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) + cmd.InSDBBuffer.Resid = int32(actualLength) + // Skip through to byte 8, Reserved + for i := 0; i < 4; i++ { + data.WriteByte(0x00) + } + + for _, lu := range cmd.Target.Devices { + if remainLength > 0 { + lun := lu.Lun + if lun > 0xff { + lun = 0x1 << 30 + } else { + lun = 0 + } + lun = (0x3fff & lun) << 16 + lun = uint64(lun << 32) + binary.Write(data, binary.BigEndian, lun) + remainLength -= 8 + } + } + return SAMStatGood +sense: + cmd.InSDBBuffer.Resid = 0 + BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB) + return SAMStatCheckCondition } -func SPCTestUnit(host int, cmd *SCSICommand) error { - return nil +func SPCStartStop(host int, cmd *SCSICommand) SAMStat { + var ( + pwrcnd, loej, start byte + ) + if err := deviceReserve(cmd); err != nil { + return SAMStatReservationConflict + } + + cmd.InSDBBuffer.Resid = 0 + scb := cmd.SCB.Bytes() + pwrcnd = scb[4] & 0xf0 + if pwrcnd != 0 { + return SAMStatGood + } + + loej = scb[4] & 0x02 + start = scb[4] & 0x01 + + if loej != 0 && start == 0 && cmd.Device.Attrs.Removable { + if luPreventRemoval(cmd.Device) { + if cmd.Device.Attrs.Online { + // online == media is present + BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_MEDIUM_REMOVAL_PREVENTED) + } else { + // !online == media is not present + BuildSenseData(cmd, NOT_READY, ASC_MEDIUM_REMOVAL_PREVENTED) + } + return SAMStatCheckCondition + } + SPCLuOffline(cmd.Device) + } + if loej != 0 && start != 0 && cmd.Device.Attrs.Removable { + SPCLuOnline(cmd.Device) + } + + return SAMStatGood } -func SPCPreventAllowMediaRemoval(host int, cmd *SCSICommand) error { - return nil +func SPCTestUnit(host int, cmd *SCSICommand) SAMStat { + if err := deviceReserve(cmd); err != nil { + return SAMStatReservationConflict + } + if cmd.Device.Attrs.Online { + return SAMStatGood + } + if cmd.Device.Attrs.Removable { + BuildSenseData(cmd, NOT_READY, ASC_MEDIUM_NOT_PRESENT) + } else { + BuildSenseData(cmd, NOT_READY, ASC_BECOMING_READY) + } + + return SAMStatCheckCondition } -func SPCModeSense(host int, cmd *SCSICommand) error { - return nil +func SPCPreventAllowMediaRemoval(host int, cmd *SCSICommand) SAMStat { + if err := deviceReserve(cmd); err != nil { + return SAMStatReservationConflict + } + // PREVENT_MASK = 0x03 + cmd.ITNexusLuInfo.Prevent = int(cmd.SCB.Bytes()[4] & 0x03) + return SAMStatGood } -func SPCServiceAction(host int, cmd *SCSICommand) error { - return nil +// SPCModeSense Implement SCSI op MODE SENSE(6) and MODE SENSE(10) +// Reference : SPC4r11 +// 6.11 - MODE SENSE(6) +// 6.12 - MODE SENSE(10) +func SPCModeSense(host int, cmd *SCSICommand) SAMStat { + return SAMStatGood } -func SPCPRReadKeys(host int, cmd *SCSICommand) error { - return nil +func SPCSendDiagnostics(host int, cmd *SCSICommand) SAMStat { + // we only support SELF-TEST==1 + if cmd.SCB.Bytes()[1]&0x04 == 0 { + goto sense + } + + return SAMStatGood +sense: + cmd.InSDBBuffer.Resid = 0 + BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB) + return SAMStatCheckCondition } -func SPCPRReadReservation(host int, cmd *SCSICommand) error { - return nil +// This is useful for the various commands using the SERVICE ACTION format. +func SPCServiceAction(host int, cmd *SCSICommand) SAMStat { + // TODO + return SAMStatGood } -func SPCPRReportCapabilities(host int, cmd *SCSICommand) error { - return nil +func SPCPRReadKeys(host int, cmd *SCSICommand) SAMStat { + allocationLength := util.GetUnalignedUint32(cmd.SCB.Bytes()[7:9]) + if allocationLength < 8 { + goto sense + } + if cmd.InSDBBuffer.Length < allocationLength { + goto sense + } + // TODO +sense: + cmd.InSDBBuffer.Resid = 0 + BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB) + return SAMStatCheckCondition } -func SPCPRRegister(host int, cmd *SCSICommand) error { - return nil +func SPCPRReadReservation(host int, cmd *SCSICommand) SAMStat { + return SAMStatGood } -func SPCPRReserve(host int, cmd *SCSICommand) error { - return nil +func SPCPRReportCapabilities(host int, cmd *SCSICommand) SAMStat { + var ( + buf []byte = make([]byte, 8) + availLength uint32 = 8 + actualLength uint32 = 0 + data *bytes.Buffer = cmd.InSDBBuffer.Buffer + ) + allocationLength := util.GetUnalignedUint32(cmd.SCB.Bytes()[7:9]) + if allocationLength < 8 { + goto sense + } + if cmd.InSDBBuffer.Length < allocationLength { + goto sense + } + binary.BigEndian.PutUint16(buf[0:2], uint16(8)) + // Persistent Reservation Type Mask format + // Type Mask Valid (TMV) + buf[3] |= 0x80 + // PR_TYPE_EXCLUSIVE_ACCESS_ALLREG + buf[4] |= 0x80 + // PR_TYPE_EXCLUSIVE_ACCESS_REGONLY + buf[4] |= 0x40 + // PR_TYPE_WRITE_EXCLUSIVE_REGONLY + buf[4] |= 0x20 + // PR_TYPE_EXCLUSIVE_ACCESS + buf[4] |= 0x08 + // PR_TYPE_WRITE_EXCLUSIVE + buf[4] |= 0x02 + // PR_TYPE_EXCLUSIVE_ACCESS_ALLREG + buf[5] |= 0x01 + + if err := binary.Write(data, binary.BigEndian, buf); err != nil { + goto sense + } else { + actualLength = availLength + } + cmd.InSDBBuffer.Resid = int32(actualLength) + return SAMStatGood +sense: + cmd.InSDBBuffer.Resid = 0 + BuildSenseData(cmd, ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CDB) + return SAMStatCheckCondition } -func SPCPRRelease(host int, cmd *SCSICommand) error { - return nil +func SPCPRRegister(host int, cmd *SCSICommand) SAMStat { + return SAMStatGood } -func SPCPRClear(host int, cmd *SCSICommand) error { - return nil +func SPCPRReserve(host int, cmd *SCSICommand) SAMStat { + return SAMStatGood } -func SPCPRPreempt(host int, cmd *SCSICommand) error { - return nil +func SPCPRRelease(host int, cmd *SCSICommand) SAMStat { + return SAMStatGood } -func SPCPRRegisterAndMove(host int, cmd *SCSICommand) error { - return nil +func SPCPRClear(host int, cmd *SCSICommand) SAMStat { + return SAMStatGood } -func SPCRequestSense(host int, cmd *SCSICommand) error { - return nil +func SPCPRPreempt(host int, cmd *SCSICommand) SAMStat { + return SAMStatGood } -func SPCSendDiagnostics(host int, cmd *SCSICommand) error { - return nil +func SPCPRRegisterAndMove(host int, cmd *SCSICommand) SAMStat { + return SAMStatGood +} + +func SPCRequestSense(host int, cmd *SCSICommand) SAMStat { + var ( + allocationLength uint32 + actualLength uint32 + ) + + allocationLength = util.GetUnalignedUint32(cmd.SCB.Bytes()[4:8]) + if allocationLength > cmd.InSDBBuffer.Length { + allocationLength = cmd.InSDBBuffer.Length + } + BuildSenseData(cmd, NO_SENSE, NO_ADDITIONAL_SENSE) + if cmd.SenseLength < allocationLength { + actualLength = cmd.SenseLength + } else { + actualLength = allocationLength + } + binary.Write(cmd.InSDBBuffer.Buffer, binary.BigEndian, cmd.SenseBuffer.Bytes()[0:actualLength]) + cmd.InSDBBuffer.Resid = int32(actualLength) + + // reset sense buffer in cmnd + cmd.SenseBuffer = &bytes.Buffer{} + cmd.SenseLength = 0 + + return SAMStatGood } diff --git a/pkg/scsi/spc_test.go b/pkg/scsi/spc_test.go new file mode 100644 index 0000000..6ef6095 --- /dev/null +++ b/pkg/scsi/spc_test.go @@ -0,0 +1,73 @@ +/* +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. +*/ + +// SCSI primary command processing test +package scsi + +import ( + "bytes" + "encoding/binary" + "testing" +) + +// Test SPCReportLuns function +func TestSPCReportLuns(t *testing.T) { + // make a fake REPORT_LUNS command + cmd := new(SCSICommand) + device := new(SCSILu) + cmd.Device = device + lu := new(SCSILu) + target := new(SCSITarget) + target.Devices = append(target.Devices, *lu) + cmd.Target = target + cmd.SCB = &bytes.Buffer{} + cmd.SenseBuffer = &bytes.Buffer{} + cmd.InSDBBuffer.Length = 16 + cmd.InSDBBuffer.Buffer = &bytes.Buffer{} + cmd.SCB.WriteByte(byte(REPORT_LUNS)) + for i := 0; i < 5; i++ { + cmd.SCB.WriteByte(0x00) + } + binary.Write(cmd.SCB, binary.BigEndian, uint32(16)) + + if err := SPCReportLuns(0, cmd); err.Err != nil { + t.Errorf("Expected not error, but got %v", err) + } + + cmd.InSDBBuffer.Length = 10 + if err := SPCReportLuns(0, cmd); err.Err == nil { + t.Error("Expected error, but got nothing") + } + + cmd.SCB = &bytes.Buffer{} + cmd.SCB.WriteByte(byte(REPORT_LUNS)) + for i := 0; i < 5; i++ { + cmd.SCB.WriteByte(0x00) + } + binary.Write(cmd.SCB, binary.BigEndian, uint32(10)) + if err := SPCReportLuns(0, cmd); err.Err == nil { + t.Error("Expected error, but got nothing") + } +} + +func TestSPCStartStop(t *testing.T) { +} + +func TestSPCTestUnit(t *testing.T) { +} + +func TestSPCPreventAllowMediaRemoval(t *testing.T) { +} diff --git a/pkg/scsi/target.go b/pkg/scsi/target.go index 30267c0..1a76a49 100644 --- a/pkg/scsi/target.go +++ b/pkg/scsi/target.go @@ -16,6 +16,12 @@ limitations under the License. package scsi +import ( + "fmt" + + "github.com/golang/glog" +) + type SCSITargetState int var ( @@ -32,9 +38,52 @@ const ( PR_EA_FN = (1 << 0) ) -type SCSITarget struct { - Name string - TID int - LID int - State SCSITargetState +type ITNexus struct { + ID uint64 + Ctime uint64 + Commands []SCSICommand + Target *SCSITarget + Host int + Info string +} + +type ITNexusLuInfo struct { + Lu *SCSILu + ID uint64 + Prevent int +} + +type SCSITarget struct { + Name string + TID int + LID int + State SCSITargetState + Devices []SCSILu + ITNexus []ITNexus +} + +func deviceReserve(cmd *SCSICommand) error { + var lu *SCSILu + for _, dev := range cmd.Target.Devices { + if dev.Lun == cmd.Device.Lun { + lu = &dev + break + } + } + if lu == nil { + glog.Errorf("invalid target and lun %d %s", cmd.Target.TID, cmd.Device.Lun) + return nil + } + + if lu.ReserveID != 0 && lu.ReserveID != cmd.CommandITNID { + glog.Errorf("already reserved %d, %d", lu.ReserveID, cmd.CommandITNID) + return fmt.Errorf("already reserved") + } + lu.ReserveID = cmd.CommandITNID + return nil +} + +func deviceRelease(tid int, itn, lun uint64, force bool) error { + // TODO + return nil } diff --git a/pkg/util/util.go b/pkg/util/util.go index afdbae3..33b5bce 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -16,6 +16,20 @@ limitations under the License. package util +import "encoding/binary" + +func GetUnalignedUint16(u8 []uint8) uint16 { + return binary.BigEndian.Uint16(u8) +} + +func GetUnalignedUint32(u8 []uint8) uint32 { + return binary.BigEndian.Uint32(u8) +} + +func GetUnalignedUint64(u8 []uint8) uint64 { + return binary.BigEndian.Uint64(u8) +} + // ParseKVText parses iSCSI key value data. func ParseKVText(txt []byte) map[string]string { m := make(map[string]string) From c5d68b38b2e6990f7a264abb7e37003b9df8977c Mon Sep 17 00:00:00 2001 From: Lei Xue Date: Mon, 2 May 2016 22:11:33 +0800 Subject: [PATCH 2/3] run the basic process with iscsi driver --- citd.go | 58 ++++- pkg/api/types.go | 307 ++++++++++++++++++++++++++ pkg/port/interfaces.go | 70 ++++++ pkg/port/iscsit/{packet.go => cmd.go} | 280 +++++++++++++++++------ pkg/port/iscsit/iscsit.go | 118 +++++++++- pkg/port/iscsit/login.go | 18 +- pkg/port/iscsit/logout.go | 18 +- pkg/port/iscsit/session.go | 5 +- pkg/scsi/backingstore.go | 26 ++- pkg/scsi/backingstore/null.go | 8 +- pkg/scsi/cmd.go | 147 ------------ pkg/scsi/drivers.go | 73 ------ pkg/scsi/lun.go | 52 +---- pkg/scsi/sbc.go | 173 ++++++++------- pkg/scsi/scsi.go | 79 +------ pkg/scsi/spc.go | 99 +++++---- pkg/scsi/target.go | 50 +---- 17 files changed, 948 insertions(+), 633 deletions(-) create mode 100644 pkg/api/types.go create mode 100644 pkg/port/interfaces.go rename pkg/port/iscsit/{packet.go => cmd.go} (57%) diff --git a/citd.go b/citd.go index 5df3aef..ef2bfed 100644 --- a/citd.go +++ b/citd.go @@ -19,13 +19,69 @@ package main import ( "net" + "os" + "reflect" "github.com/golang/glog" + "github.com/gostor/gotgt/pkg/api" + "github.com/gostor/gotgt/pkg/scsi" ) func main() { - _, err := net.Listen("tcp", ":3260") + l, err := net.Listen("tcp", ":3260") if err != nil { glog.Error(err) + os.Exit(1) + } + defer l.Close() + t, err := scsi.NewTarget(0, "iscsi", "test-iscsi-target") + if err != nil { + glog.Error(err) + os.Exit(1) + } + conns := make(map[string]net.Conn) + + for { + glog.Info("Listening ...") + conn, err := l.Accept() + checkError(err, "Accept") + glog.Info("Accepting ...") + conns[conn.RemoteAddr().String()] = conn + // start a new thread to do with this command + go Handler(conn, t) + } +} + +func checkError(err error, info string) (res bool) { + + if err != nil { + glog.Error(info + " " + err.Error()) + return false + } + return true +} + +func Handler(conn net.Conn, tgt *api.SCSITarget) { + + glog.Infof("connection is connected from %s...\n", conn.RemoteAddr().String()) + + buf := make([]byte, 1024) + for { + lenght, err := conn.Read(buf) + if checkError(err, "Connection") == false { + conn.Close() + break + } + if lenght > 0 { + buf[lenght] = 0 + } + v := reflect.ValueOf(tgt.SCSITargetDriver) + iscsit := v.MethodByName("ProcessCommand") + in := make([]reflect.Value, 1) + in[0] = reflect.ValueOf(buf[0:lenght]) + res := iscsit.Call(in)[0] + b := res.Bytes() + glog.Infof("%s\n", string(b)) + conn.Write(b) } } diff --git a/pkg/api/types.go b/pkg/api/types.go new file mode 100644 index 0000000..12430e2 --- /dev/null +++ b/pkg/api/types.go @@ -0,0 +1,307 @@ +package api + +import ( + "bytes" + "errors" +) + +type SCSICommandType byte + +var ( + TEST_UNIT_READY SCSICommandType = 0x00 + REZERO_UNIT SCSICommandType = 0x01 + REQUEST_SENSE SCSICommandType = 0x03 + FORMAT_UNIT SCSICommandType = 0x04 + READ_BLOCK_LIMITS SCSICommandType = 0x05 + REASSIGN_BLOCKS SCSICommandType = 0x07 + INITIALIZE_ELEMENT_STATUS SCSICommandType = 0x07 + READ_6 SCSICommandType = 0x08 + WRITE_6 SCSICommandType = 0x0a + SEEK_6 SCSICommandType = 0x0b + READ_REVERSE SCSICommandType = 0x0f + WRITE_FILEMARKS SCSICommandType = 0x10 + SPACE SCSICommandType = 0x11 + INQUIRY SCSICommandType = 0x12 + RECOVER_BUFFERED_DATA SCSICommandType = 0x14 + MODE_SELECT SCSICommandType = 0x15 + RESERVE SCSICommandType = 0x16 + RELEASE SCSICommandType = 0x17 + COPY SCSICommandType = 0x18 + ERASE SCSICommandType = 0x19 + MODE_SENSE SCSICommandType = 0x1a + START_STOP SCSICommandType = 0x1b + RECEIVE_DIAGNOSTIC SCSICommandType = 0x1c + SEND_DIAGNOSTIC SCSICommandType = 0x1d + ALLOW_MEDIUM_REMOVAL SCSICommandType = 0x1e + + SET_WINDOW SCSICommandType = 0x24 + READ_CAPACITY SCSICommandType = 0x25 + READ_10 SCSICommandType = 0x28 + WRITE_10 SCSICommandType = 0x2a + SEEK_10 SCSICommandType = 0x2b + POSITION_TO_ELEMENT SCSICommandType = 0x2b + WRITE_VERIFY SCSICommandType = 0x2e + VERIFY_10 SCSICommandType = 0x2f + SEARCH_HIGH SCSICommandType = 0x30 + SEARCH_EQUAL SCSICommandType = 0x31 + SEARCH_LOW SCSICommandType = 0x32 + SET_LIMITS SCSICommandType = 0x33 + PRE_FETCH_10 SCSICommandType = 0x34 + READ_POSITION SCSICommandType = 0x34 + SYNCHRONIZE_CACHE SCSICommandType = 0x35 + LOCK_UNLOCK_CACHE SCSICommandType = 0x36 + READ_DEFECT_DATA SCSICommandType = 0x37 + INITIALIZE_ELEMENT_STATUS_WITH_RANGE SCSICommandType = 0x37 + MEDIUM_SCAN SCSICommandType = 0x38 + COMPARE SCSICommandType = 0x39 + COPY_VERIFY SCSICommandType = 0x3a + WRITE_BUFFER SCSICommandType = 0x3b + READ_BUFFER SCSICommandType = 0x3c + UPDATE_BLOCK SCSICommandType = 0x3d + READ_LONG SCSICommandType = 0x3e + WRITE_LONG SCSICommandType = 0x3f + CHANGE_DEFINITION SCSICommandType = 0x40 + WRITE_SAME SCSICommandType = 0x41 + UNMAP SCSICommandType = 0x42 + READ_TOC SCSICommandType = 0x43 + GET_CONFIGURATION SCSICommandType = 0x46 + LOG_SELECT SCSICommandType = 0x4c + LOG_SENSE SCSICommandType = 0x4d + READ_DISK_INFO SCSICommandType = 0x51 + READ_TRACK_INFO SCSICommandType = 0x52 + MODE_SELECT_10 SCSICommandType = 0x55 + RESERVE_10 SCSICommandType = 0x56 + RELEASE_10 SCSICommandType = 0x57 + MODE_SENSE_10 SCSICommandType = 0x5a + CLOSE_TRACK SCSICommandType = 0x5b + READ_BUFFER_CAP SCSICommandType = 0x5c + PERSISTENT_RESERVE_IN SCSICommandType = 0x5e + PERSISTENT_RESERVE_OUT SCSICommandType = 0x5f + VARLEN_CDB SCSICommandType = 0x7f + READ_16 SCSICommandType = 0x88 + COMPARE_AND_WRITE SCSICommandType = 0x89 + WRITE_16 SCSICommandType = 0x8a + ORWRITE_16 SCSICommandType = 0x8b + WRITE_VERIFY_16 SCSICommandType = 0x8e + VERIFY_16 SCSICommandType = 0x8f + PRE_FETCH_16 SCSICommandType = 0x90 + SYNCHRONIZE_CACHE_16 SCSICommandType = 0x91 + WRITE_SAME_16 SCSICommandType = 0x93 + SERVICE_ACTION_IN SCSICommandType = 0x9e + SAI_READ_CAPACITY_16 SCSICommandType = 0x10 + SAI_GET_LBA_STATUS SCSICommandType = 0x12 + REPORT_LUNS SCSICommandType = 0xa0 + MAINT_PROTOCOL_IN SCSICommandType = 0xa3 + MOVE_MEDIUM SCSICommandType = 0xa5 + EXCHANGE_MEDIUM SCSICommandType = 0xa6 + READ_12 SCSICommandType = 0xa8 + WRITE_12 SCSICommandType = 0xaa + GET_PERFORMACE SCSICommandType = 0xac + READ_DVD_STRUCTURE SCSICommandType = 0xad + WRITE_VERIFY_12 SCSICommandType = 0xae + VERIFY_12 SCSICommandType = 0xaf + SEARCH_HIGH_12 SCSICommandType = 0xb0 + SEARCH_EQUAL_12 SCSICommandType = 0xb1 + SEARCH_LOW_12 SCSICommandType = 0xb2 + READ_ELEMENT_STATUS SCSICommandType = 0xb8 + SEND_VOLUME_TAG SCSICommandType = 0xb6 + SET_STREAMING SCSICommandType = 0xb6 + SET_CD_SPEED SCSICommandType = 0xbb + WRITE_LONG_2 SCSICommandType = 0xea +) + +type SCSITargetState int + +var ( + TargetOnline SCSITargetState = 1 + TargetReady SCSITargetState = 2 +) + +type SCSIDataDirection int + +const ( + SCSIDataNone = iota + SCSIDataWrite + SCSIDataRead + SCSIDataBidirection +) + +type SCSIDataBuffer struct { + Buffer *bytes.Buffer + Length uint32 + TransferLength uint32 + Resid int32 +} + +type SCSICommand struct { + Target *SCSITarget + DeviceID uint64 + Device *SCSILu + State uint64 + Direction SCSIDataDirection + InSDBBuffer SCSIDataBuffer + OutSDBBuffer SCSIDataBuffer + // Command ITN ID + CommandITNID uint64 + Offset uint64 + TL uint32 + SCB *bytes.Buffer + SCBLength int + Lun []uint8 + Attribute int + Tag uint64 + Result byte + SenseBuffer *bytes.Buffer + SenseLength uint32 + ITNexus *ITNexus + ITNexusLuInfo *ITNexusLuInfo +} +type ITNexus struct { + ID uint64 + Ctime uint64 + Commands []SCSICommand + Target *SCSITarget + Host int + Info string +} + +type ITNexusLuInfo struct { + Lu *SCSILu + ID uint64 + Prevent int +} + +type SCSITarget struct { + Name string + TID int + LID int + State SCSITargetState + Devices []SCSILu + ITNexus []ITNexus + + SCSITargetDriver interface{} +} + +type SCSITargetDriverState int + +const ( + // just registered + SCSI_DRIVER_REGD = iota + // initialized ok + SCSI_DRIVER_INIT + // failed to initialize + SCSI_DRIVER_ERR + // exited + SCSI_DRIVER_EXIT +) + +type SCSITargetDriverCommon struct { + Name string + State SCSITargetDriverState + DefaultBST string +} + +type SCSILuPhyAttribute struct { + SCSIID string + SCSISN string + NumID uint64 + VendorID string + ProductID string + ProductRev string + VersionDesction []uint16 + // Peripheral device type + DeviceType uint + // Peripheral Qualifier + Qualifier bool + // Removable media + Removable bool + // Read Only media + Readonly bool + // Software Write Protect + SWP bool + // Use thin-provisioning for this LUN + Thinprovisioning bool + // Logical Unit online + Online bool + // Descrptor format sense data supported + SenseFormat bool + // Logical blocks per physical block exponent + Lbppbe int + // Do not update it automatically when the backing file changes + NoLbppbe int + // Lowest aligned LBA + LowestAlignedLBA int +} + +var ( + DefaultBlockShift int = 9 + DefaultSenseBufferSize int = 252 +) + +var ( + SAM_STAT_GOOD byte = 0x00 + SAM_STAT_CHECK_CONDITION byte = 0x02 + SAM_STAT_CONDITION_MET byte = 0x04 + SAM_STAT_BUSY byte = 0x08 + SAM_STAT_INTERMEDIATE byte = 0x10 + SAM_STAT_INTERMEDIATE_CONDITION_MET byte = 0x14 + SAM_STAT_RESERVATION_CONFLICT byte = 0x18 + SAM_STAT_COMMAND_TERMINATED byte = 0x22 + SAM_STAT_TASK_SET_FULL byte = 0x28 + SAM_STAT_ACA_ACTIVE byte = 0x30 + SAM_STAT_TASK_ABORTED byte = 0x40 +) + +type SAMStat struct { + Stat byte + Err error +} + +var ( + SAMStatGood = SAMStat{SAM_STAT_GOOD, nil} + SAMStatCheckCondition = SAMStat{SAM_STAT_CHECK_CONDITION, errors.New("check condition")} + SAMStatConditionMet = SAMStat{SAM_STAT_CONDITION_MET, errors.New("condition met")} + SAMStatBusy = SAMStat{SAM_STAT_BUSY, errors.New("busy")} + SAMStatIntermediate = SAMStat{SAM_STAT_INTERMEDIATE, errors.New("intermediate")} + SAMStatIntermediateConditionMet = SAMStat{SAM_STAT_INTERMEDIATE_CONDITION_MET, errors.New("intermediate condition met")} + SAMStatReservationConflict = SAMStat{SAM_STAT_RESERVATION_CONFLICT, errors.New("reservation conflict")} + SAMStatCommandTerminated = SAMStat{SAM_STAT_COMMAND_TERMINATED, errors.New("command terminated")} + SAMStatTaskSetFull = SAMStat{SAM_STAT_TASK_SET_FULL, errors.New("task set full")} + SAMStatAcaActive = SAMStat{SAM_STAT_ACA_ACTIVE, errors.New("aca active")} + SAMStatTaskAborted = SAMStat{SAM_STAT_TASK_ABORTED, errors.New("task aborted")} +) + +type SCSIDeviceType byte + +var ( + TYPE_DISK SCSIDeviceType = 0x00 + TYPE_TAPE SCSIDeviceType = 0x01 + TYPE_PRINTER SCSIDeviceType = 0x02 + TYPE_PROCESSOR SCSIDeviceType = 0x03 + TYPE_WORM SCSIDeviceType = 0x04 + TYPE_MMC SCSIDeviceType = 0x05 + TYPE_SCANNER SCSIDeviceType = 0x06 + TYPE_MOD SCSIDeviceType = 0x07 + + TYPE_MEDIUM_CHANGER SCSIDeviceType = 0x08 + TYPE_COMM SCSIDeviceType = 0x09 + TYPE_RAID SCSIDeviceType = 0x0c + TYPE_ENCLOSURE SCSIDeviceType = 0x0d + TYPE_RBC SCSIDeviceType = 0x0e + TYPE_OSD SCSIDeviceType = 0x11 + TYPE_NO_LUN SCSIDeviceType = 0x7f + + TYPE_PT SCSIDeviceType = 0xff +) + +type SCSILu struct { + FD int + Address uint64 + Size uint64 + Lun uint64 + Path string + BsoFlags int + BlockShift uint + ReserveID uint64 + Attrs SCSILuPhyAttribute +} diff --git a/pkg/port/interfaces.go b/pkg/port/interfaces.go new file mode 100644 index 0000000..b2e6b94 --- /dev/null +++ b/pkg/port/interfaces.go @@ -0,0 +1,70 @@ +package port + +import ( + "github.com/gostor/gotgt/pkg/api" + "github.com/gostor/gotgt/pkg/port/iscsit" +) + +type SCSITargetDriver interface { + Init() error + Exit() error + + CreateTarget(target *api.SCSITarget) error + DestroyTarget(target *api.SCSITarget) error + CreatePortal(name string) error + DestroyPortal(name string) error + CreateLu(lu *api.SCSILu) error + GetLu(lun uint8) (uint64, error) + + ProcessCommand(buf []byte) ([]byte, error) + CommandNotify(nid uint64, result int, cmd *api.SCSICommand) error +} + +type fakeSCSITargetDriver struct { + api.SCSITargetDriverCommon +} + +func (fake *fakeSCSITargetDriver) Init() error { + return nil +} + +func (fake *fakeSCSITargetDriver) Exit() error { + return nil +} + +func (fake *fakeSCSITargetDriver) CreateTarget(target *api.SCSITarget) error { + return nil +} + +func (fake *fakeSCSITargetDriver) DestroyTarget(target *api.SCSITarget) error { + return nil +} + +func (fake *fakeSCSITargetDriver) CreatePortal(name string) error { + return nil +} + +func (fake *fakeSCSITargetDriver) DestroyPortal(name string) error { + return nil +} + +func (fake *fakeSCSITargetDriver) CreateLu(lu *api.SCSILu) error { + return nil +} + +func (fake *fakeSCSITargetDriver) GetLun(lun uint8) (uint64, error) { + return 0, nil +} +func (fake *fakeSCSITargetDriver) CommandNotify(nid uint64, result int, cmd *api.SCSICommand) error { + return nil +} +func (fake *fakeSCSITargetDriver) ProcessCommand(buf []byte) ([]byte, error) { + return []byte(""), nil +} + +func NewTargetDriver(driver string, tgt *api.SCSITarget) SCSITargetDriver { + if driver == "iscsi" { + return iscsit.NewISCSITarget(tgt) + } + return nil +} diff --git a/pkg/port/iscsit/packet.go b/pkg/port/iscsit/cmd.go similarity index 57% rename from pkg/port/iscsit/packet.go rename to pkg/port/iscsit/cmd.go index e502051..69b674a 100644 --- a/pkg/port/iscsit/packet.go +++ b/pkg/port/iscsit/cmd.go @@ -1,26 +1,8 @@ -/* -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 packet implements the iSCSI PDU packet format as specified in -// rfc7143 section 11. package iscsit import ( + "bytes" "fmt" - "io" "strings" ) @@ -70,15 +52,7 @@ var opCodeMap = map[OpCode]string{ OpReject: "Reject", } -func (c OpCode) String() string { - s := opCodeMap[c] - if s == "" { - s = fmt.Sprintf("Unknown Code: %x", int(c)) - } - return s -} - -type Message struct { +type ISCSICommand struct { OpCode OpCode RawHeader []byte DataLen int @@ -109,8 +83,8 @@ type Message struct { // SCSI commands ExpectedDataLen uint32 CDB []byte - Status Status - SCSIResponse Response + Status byte + SCSIResponse byte // Data-In HasStatus bool @@ -118,23 +92,23 @@ type Message struct { BufferOffset uint32 } -func (m *Message) Bytes() []byte { - switch m.OpCode { +func (cmd *ISCSICommand) Bytes() []byte { + switch cmd.OpCode { case OpLoginResp: - return m.loginRespBytes() + return cmd.loginRespBytes() case OpLogoutResp: - return m.logoutRespBytes() + return cmd.logoutRespBytes() case OpSCSIResp: - return m.scsiCmdRespBytes() + return cmd.scsiCmdRespBytes() case OpSCSIIn: - return m.dataInBytes() + return cmd.dataInBytes() } return nil } -func (m *Message) String() string { +func (m *ISCSICommand) String() string { var s []string - s = append(s, fmt.Sprintf("Op: %v", m.OpCode)) + s = append(s, fmt.Sprintf("Op: %v", opCodeMap[m.OpCode])) s = append(s, fmt.Sprintf("Final = %v", m.Final)) s = append(s, fmt.Sprintf("Immediate = %v", m.Immediate)) s = append(s, fmt.Sprintf("Data Segment Length = %d", m.DataLen)) @@ -171,37 +145,6 @@ func (m *Message) String() string { return strings.Join(s, "\n") } -// Response composes a reply to the given message with the appropriate bits set. -func (m *Message) Response(r *Message) { - r.TaskTag = m.TaskTag - r.ConnID = m.ConnID - r.ISID = m.ISID -} - -func Next(r io.Reader) (*Message, error) { - buf := make([]byte, 48) // TODO: sync.Pool - if _, err := io.ReadFull(r, buf); err != nil { - return nil, err - } - m, err := parseHeader(buf) - if err != nil { - return nil, err - } - m.RawHeader = buf - if m.DataLen > 0 { - dl := m.DataLen - for dl%4 > 0 { - dl++ - } - data := make([]byte, dl) - if _, err := io.ReadFull(r, data); err != nil { - return nil, err - } - m.RawData = data[:m.DataLen] - } - return m, nil -} - // parseUint parses the given slice as a network-byte-ordered integer. If // there are more than 8 bytes in data, it overflows. func ParseUint(data []byte) uint64 { @@ -220,13 +163,12 @@ func MarshalUint64(i uint64) []byte { } return data } - -func parseHeader(data []byte) (*Message, error) { +func parseHeader(data []byte) (*ISCSICommand, error) { if len(data) != 48 { return nil, fmt.Errorf("garbled header") } // TODO: sync.Pool - m := &Message{} + m := &ISCSICommand{} m.Immediate = 0x40&data[0] == 0x40 m.OpCode = OpCode(data[0] & 0x3f) m.Final = 0x80&data[1] == 0x80 @@ -274,3 +216,197 @@ func parseHeader(data []byte) (*Message, error) { } return m, nil } + +func (m *ISCSICommand) scsiCmdRespBytes() []byte { + // rfc7143 11.4 + buf := &bytes.Buffer{} + buf.WriteByte(byte(OpSCSIResp)) + buf.WriteByte(0x80) // 11.4.1 = wtf + buf.WriteByte(byte(m.SCSIResponse)) + buf.WriteByte(byte(m.Status)) + + // Skip through to byte 16 + for i := 0; i < 3*4; i++ { + buf.WriteByte(0x00) + } + buf.Write(MarshalUint64(uint64(m.TaskTag))[4:]) + for i := 0; i < 4; i++ { + buf.WriteByte(0x00) + } + buf.Write(MarshalUint64(uint64(m.StatSN))[4:]) + buf.Write(MarshalUint64(uint64(m.ExpCmdSN))[4:]) + buf.Write(MarshalUint64(uint64(m.MaxCmdSN))[4:]) + for i := 0; i < 3*4; i++ { + buf.WriteByte(0x00) + } + + return buf.Bytes() +} + +func (m *ISCSICommand) dataInBytes() []byte { + // rfc7143 11.7 + buf := &bytes.Buffer{} + buf.WriteByte(byte(OpSCSIIn)) + var b byte + b = 0x80 + if m.HasStatus { + b |= 0x01 + } + buf.WriteByte(b) + buf.WriteByte(0x00) + if m.HasStatus { + b = byte(m.Status) + } + buf.WriteByte(b) + + buf.WriteByte(0x00) // 4 + buf.Write(MarshalUint64(uint64(len(m.RawData)))[5:]) // 5-8 + buf.WriteByte(0x00) + buf.WriteByte(byte(m.LUN)) + // Skip through to byte 16 + for i := 0; i < 6; i++ { + buf.WriteByte(0x00) + } + buf.Write(MarshalUint64(uint64(m.TaskTag))[4:]) + for i := 0; i < 4; i++ { + // 11.7.4 + buf.WriteByte(0xff) + } + buf.Write(MarshalUint64(uint64(m.StatSN))[4:]) + buf.Write(MarshalUint64(uint64(m.ExpCmdSN))[4:]) + buf.Write(MarshalUint64(uint64(m.MaxCmdSN))[4:]) + buf.Write(MarshalUint64(uint64(m.DataSN))[4:]) + buf.Write(MarshalUint64(uint64(m.BufferOffset))[4:]) + for i := 0; i < 4; i++ { + buf.WriteByte(0x00) + } + buf.Write(m.RawData) + dl := len(m.RawData) + for dl%4 > 0 { + dl++ + buf.WriteByte(0x00) + } + + return buf.Bytes() +} + +type InquiryData struct { + PeripheralQualifier int + PeripheralType int + Removable bool + Version int + SupportsACA bool + Hierarchical bool + SupportsSCC bool + HasACC bool + TargetGroupSupport int + ThirdPartyCopy bool + Protect bool + EnclosureServices bool + Multiport bool + MediaChanger bool + Vendor [8]byte + Product [16]byte + RevisionLevel [4]byte + SerialNumber uint64 +} + +func (id *InquiryData) bytes() []byte { + buf := &bytes.Buffer{} + var b byte + b = (uint8(id.PeripheralQualifier) << 5) & 0xe0 + b |= uint8(id.PeripheralType) & 0x1f + buf.WriteByte(b) + b = 0 + if id.Removable { + b = 0x80 + } + buf.WriteByte(b) + buf.WriteByte(byte(id.Version)) + b = 0x02 + if id.SupportsACA { + b |= 0x20 + } + if id.Hierarchical { + b |= 0x10 + } + buf.WriteByte(b) + buf.WriteByte(0x00) + // byte 5 + b = 0 + if id.SupportsSCC { + b |= 0x80 + } + if id.HasACC { + b |= 0x40 + } + b |= byte(id.TargetGroupSupport) << 4 & 0x30 + if id.ThirdPartyCopy { + b |= 0x08 + } + if id.Protect { + b |= 0x01 + } + buf.WriteByte(b) + // byte 6 + b = 0 + if id.EnclosureServices { + b |= 0x40 + } + if id.Multiport { + b |= 0x10 + } + if id.MediaChanger { + b |= 0x08 + } + buf.WriteByte(b) + buf.WriteByte(0x02) + buf.Write(id.Vendor[:]) + buf.Write(id.Product[:]) + buf.Write(id.RevisionLevel[:]) + buf.Write(MarshalUint64(id.SerialNumber)) + for i := 0; i < 12; i++ { + buf.WriteByte(0x00) + } + data := buf.Bytes() + data[4] = byte(len(data) - 4) + return data +} + +type Capacity struct { + LBA uint64 + Blocksize uint32 + ProtectionType uint8 + PIExponent uint8 + LogicalExponent uint8 + ThinProvisioned bool + ThinProvReturnsZeros bool + LowestLBA uint16 +} + +func (c *Capacity) bytes() []byte { + // table 111 + // http://www.seagate.com/staticfiles/support/disc/manuals/Interface%20manuals/100293068c.pdf + buf := &bytes.Buffer{} + buf.Write(MarshalUint64(c.LBA)) + buf.Write(MarshalUint64(uint64(c.Blocksize))[4:]) + var b byte + if c.ProtectionType > 0 { + b |= 0x01 + b |= c.ProtectionType << 1 + b &= 0x0f + } + buf.WriteByte(b) + b = c.PIExponent << 4 + b |= c.LogicalExponent + buf.WriteByte(b) + lowLBA := MarshalUint64(uint64(c.LowestLBA))[6:] + lowLBA[0] &= 0x3f + if c.ThinProvisioned { + lowLBA[0] &= 0x80 + } + if c.ThinProvReturnsZeros { + lowLBA[0] &= 0x40 + } + return buf.Bytes() +} diff --git a/pkg/port/iscsit/iscsit.go b/pkg/port/iscsit/iscsit.go index 3165bb8..c951234 100644 --- a/pkg/port/iscsit/iscsit.go +++ b/pkg/port/iscsit/iscsit.go @@ -17,6 +17,11 @@ limitations under the License. // iSCSI Target Driver package iscsit +import ( + "github.com/gostor/gotgt/pkg/api" + "github.com/gostor/gotgt/pkg/util" +) + type ISCSIDiscoveryMethod string var ( @@ -33,9 +38,11 @@ type ISCSIRedirectInfo struct { } type ISCSITarget struct { + *api.SCSITarget + api.SCSITargetDriverCommon + Sessions []*ISCSISession SessionParam []ISCSISessionParam - TID int Alias string MaxSessions int RedirectInfo ISCSIRedirectInfo @@ -44,41 +51,128 @@ type ISCSITarget struct { NopCount int } -type ISCSITargetDriver struct { - SCSITargetDriver +func NewISCSITarget(target *api.SCSITarget) *ISCSITarget { + return &ISCSITarget{ + SCSITarget: target, + } } -func (tgt *ISCSITargetDriver) Init() error { +func (tgt *ISCSITarget) Init() error { return nil } -func (tgt *ISCSITargetDriver) Exit() error { +func (tgt *ISCSITarget) Exit() error { return nil } -func (tgt *ISCSITargetDriver) CreateTarget(target *SCSITarget) error { +func (tgt *ISCSITarget) CreateTarget(target *api.SCSITarget) error { return nil } -func (tgt *ISCSITargetDriver) DestroyTarget(target *SCSITarget) error { +func (tgt *ISCSITarget) DestroyTarget(target *api.SCSITarget) error { return nil } -func (tgt *ISCSITargetDriver) CreatePortal(name string) error { +func (tgt *ISCSITarget) CreatePortal(name string) error { return nil } -func (tgt *ISCSITargetDriver) DestroyPortal(name string) error { +func (tgt *ISCSITarget) DestroyPortal(name string) error { return nil } -func (tgt *ISCSITargetDriver) CreateLu(lu *SCSILu) error { +func (tgt *ISCSITarget) CreateLu(lu *api.SCSILu) error { return nil } -func (tgt *ISCSITargetDriver) GetLun(lun uint8) (uint64, error) { +func (tgt *ISCSITarget) GetLu(lun uint8) (uint64, error) { return 0, nil } -func (tgt *ISCSITargetDriver) CommandNotify(nid uint64, result int, cmd *SCSICommand) error { +func (tgt *ISCSITarget) CommandNotify(nid uint64, result int, cmd *api.SCSICommand) error { return nil } +func (tgt *ISCSITarget) ProcessCommand(buf []byte) ([]byte, error) { + b := make([]byte, 48) // TODO: sync.Pool + b = buf[0:48] + m, err := parseHeader(b) + if err != nil { + return nil, err + } + m.RawHeader = b + if m.DataLen > 0 { + m.RawData = buf[48:m.DataLen] + } + resp := &ISCSICommand{} + switch m.OpCode { + case OpLoginReq: + resp = &ISCSICommand{ + OpCode: OpLoginResp, + Transit: true, + NSG: FullFeaturePhase, + StatSN: m.ExpStatSN, + TaskTag: m.TaskTag, + ExpCmdSN: m.CmdSN, + MaxCmdSN: m.CmdSN, + RawData: util.MarshalKVText(map[string]string{ + "HeaderDigest": "None", + "DataDigest": "None", + }), + } + break + case OpSCSICmd: + resp = &ISCSICommand{ + OpCode: OpSCSIResp, + Final: true, + StatSN: m.ExpStatSN, + TaskTag: m.TaskTag, + ExpCmdSN: m.CmdSN + 1, + MaxCmdSN: m.CmdSN + 10, + } + switch api.SCSICommandType(m.CDB[0]) { + case api.TEST_UNIT_READY: + // test unit ready + resp.Status = api.SAM_STAT_GOOD + resp.SCSIResponse = 0x01 + break + case api.READ_CAPACITY: + resp.OpCode = OpSCSIIn + resp.HasStatus = true + var data []byte + data = append(data, MarshalUint64(uint64(0))[4:]...) + data = append(data, MarshalUint64(uint64(0))[4:]...) + resp.RawData = data + break + case api.SERVICE_ACTION_IN: + resp.OpCode = OpSCSIIn + resp.HasStatus = true + sa := m.CDB[1] & 0x1f + switch sa { + case 0x10: + c := &Capacity{} + resp.RawData = c.bytes() + } + break + case api.INQUIRY: + resp.OpCode = OpSCSIIn + resp.HasStatus = true + alloc := int(ParseUint(m.CDB[3:5])) + inq := &InquiryData{ + Vendor: [8]byte{'1', '1', 'c', 'a', 'n', 's'}, + Product: [16]byte{'c', 'o', 'f', 'f', 'e', 'e'}, + RevisionLevel: [4]byte{'1', '.', '0'}, + SerialNumber: 52, + } + + if len(inq.bytes()) >= alloc { + resp.RawData = inq.bytes()[:alloc] + } else { + resp.RawData = inq.bytes() + } + break + default: + break + } + } + b1 := resp.Bytes() + return b1, nil +} diff --git a/pkg/port/iscsit/login.go b/pkg/port/iscsit/login.go index b30d08e..3dec0d8 100644 --- a/pkg/port/iscsit/login.go +++ b/pkg/port/iscsit/login.go @@ -1,24 +1,8 @@ -/* -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 iscsit import "bytes" -func (m *Message) loginRespBytes() []byte { +func (m *ISCSICommand) loginRespBytes() []byte { // rfc7143 11.13 buf := &bytes.Buffer{} // byte 0 diff --git a/pkg/port/iscsit/logout.go b/pkg/port/iscsit/logout.go index a28e48c..3ce91f9 100644 --- a/pkg/port/iscsit/logout.go +++ b/pkg/port/iscsit/logout.go @@ -1,24 +1,8 @@ -/* -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 iscsit import "bytes" -func (m *Message) logoutRespBytes() []byte { +func (m *ISCSICommand) logoutRespBytes() []byte { buf := &bytes.Buffer{} buf.WriteByte(byte(OpLogoutResp)) buf.WriteByte(0x80) diff --git a/pkg/port/iscsit/session.go b/pkg/port/iscsit/session.go index 8705f11..b043bbb 100644 --- a/pkg/port/iscsit/session.go +++ b/pkg/port/iscsit/session.go @@ -42,6 +42,9 @@ type ISCSISession struct { Rdma int } +type ISCSIHeader struct { +} + type ISCSIPdu struct { Bhs ISCSIHeader AhsSize uint @@ -78,7 +81,7 @@ func NewISCSISession() (*ISCSISession, error) { tsih += uint16(b[0]) << 8 tsih += uint16(b[1]) - return &Session{ + return &ISCSISession{ Tsih: tsih, }, nil } diff --git a/pkg/scsi/backingstore.go b/pkg/scsi/backingstore.go index 1d9f8fc..4e585bd 100644 --- a/pkg/scsi/backingstore.go +++ b/pkg/scsi/backingstore.go @@ -16,7 +16,11 @@ limitations under the License. package scsi -import "fmt" +import ( + "fmt" + + "github.com/gostor/gotgt/pkg/api" +) type BaseBackingStore struct { Name string @@ -25,11 +29,11 @@ type BaseBackingStore struct { } type BackingStore interface { - Open(dev *SCSILu, path string, fd *int, size *uint64) error - Close(dev *SCSILu) error - Init(dev *SCSILu, Opts string) error - Exit(dev *SCSILu) error - CommandSubmit(cmd *SCSICommand) error + 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) @@ -55,22 +59,22 @@ type fakeBackingStore struct { BaseBackingStore } -func (fake *fakeBackingStore) Open(dev *SCSILu, path string, fd *int, size *uint64) error { +func (fake *fakeBackingStore) Open(dev *api.SCSILu, path string, fd *int, size *uint64) error { return nil } -func (fake *fakeBackingStore) Close(dev *SCSILu) error { +func (fake *fakeBackingStore) Close(dev *api.SCSILu) error { return nil } -func (fake *fakeBackingStore) Init(dev *SCSILu, Opts string) error { +func (fake *fakeBackingStore) Init(dev *api.SCSILu, Opts string) error { return nil } -func (fake *fakeBackingStore) Exit(dev *SCSILu) error { +func (fake *fakeBackingStore) Exit(dev *api.SCSILu) error { return nil } -func (fake *fakeBackingStore) CommandSubmit(cmd *SCSICommand) error { +func (fake *fakeBackingStore) CommandSubmit(cmd *api.SCSICommand) error { return nil } diff --git a/pkg/scsi/backingstore/null.go b/pkg/scsi/backingstore/null.go index c2fb4bb..afb7837 100644 --- a/pkg/scsi/backingstore/null.go +++ b/pkg/scsi/backingstore/null.go @@ -16,7 +16,11 @@ limitations under the License. package backingstore -import "github.com/gostor/gotgt/pkg/scsi" +import ( + "github.com/gostor/gotgt/pkg/scsi" + + "github.com/golang/glog" +) func init() { scsi.RegisterBackingStore("null", new) @@ -35,6 +39,7 @@ func new() (scsi.BackingStore, error) { } func (bs *NullBackingStore) Open(dev *SCSILu, path string, fd *int, size *uint64) error { + glog.V(1).Infof("NULL backing store open, size: %d", size) return nil } @@ -51,5 +56,6 @@ func (bs *NullBackingStore) Exit(dev *SCSILu) error { } func (bs *NullBackingStore) CommandSubmit(cmd *SCSICommand) error { + cmd.Result = SAM_STAT_GOOD return nil } diff --git a/pkg/scsi/cmd.go b/pkg/scsi/cmd.go index 0c80d5d..e50fa3a 100644 --- a/pkg/scsi/cmd.go +++ b/pkg/scsi/cmd.go @@ -16,113 +16,6 @@ limitations under the License. package scsi -import "bytes" - -type SCSICommandType byte - -var ( - TEST_UNIT_READY SCSICommandType = 0x00 - REZERO_UNIT SCSICommandType = 0x01 - REQUEST_SENSE SCSICommandType = 0x03 - FORMAT_UNIT SCSICommandType = 0x04 - READ_BLOCK_LIMITS SCSICommandType = 0x05 - REASSIGN_BLOCKS SCSICommandType = 0x07 - INITIALIZE_ELEMENT_STATUS SCSICommandType = 0x07 - READ_6 SCSICommandType = 0x08 - WRITE_6 SCSICommandType = 0x0a - SEEK_6 SCSICommandType = 0x0b - READ_REVERSE SCSICommandType = 0x0f - WRITE_FILEMARKS SCSICommandType = 0x10 - SPACE SCSICommandType = 0x11 - INQUIRY SCSICommandType = 0x12 - RECOVER_BUFFERED_DATA SCSICommandType = 0x14 - MODE_SELECT SCSICommandType = 0x15 - RESERVE SCSICommandType = 0x16 - RELEASE SCSICommandType = 0x17 - COPY SCSICommandType = 0x18 - ERASE SCSICommandType = 0x19 - MODE_SENSE SCSICommandType = 0x1a - START_STOP SCSICommandType = 0x1b - RECEIVE_DIAGNOSTIC SCSICommandType = 0x1c - SEND_DIAGNOSTIC SCSICommandType = 0x1d - ALLOW_MEDIUM_REMOVAL SCSICommandType = 0x1e - - SET_WINDOW SCSICommandType = 0x24 - READ_CAPACITY SCSICommandType = 0x25 - READ_10 SCSICommandType = 0x28 - WRITE_10 SCSICommandType = 0x2a - SEEK_10 SCSICommandType = 0x2b - POSITION_TO_ELEMENT SCSICommandType = 0x2b - WRITE_VERIFY SCSICommandType = 0x2e - VERIFY_10 SCSICommandType = 0x2f - SEARCH_HIGH SCSICommandType = 0x30 - SEARCH_EQUAL SCSICommandType = 0x31 - SEARCH_LOW SCSICommandType = 0x32 - SET_LIMITS SCSICommandType = 0x33 - PRE_FETCH_10 SCSICommandType = 0x34 - READ_POSITION SCSICommandType = 0x34 - SYNCHRONIZE_CACHE SCSICommandType = 0x35 - LOCK_UNLOCK_CACHE SCSICommandType = 0x36 - READ_DEFECT_DATA SCSICommandType = 0x37 - INITIALIZE_ELEMENT_STATUS_WITH_RANGE SCSICommandType = 0x37 - MEDIUM_SCAN SCSICommandType = 0x38 - COMPARE SCSICommandType = 0x39 - COPY_VERIFY SCSICommandType = 0x3a - WRITE_BUFFER SCSICommandType = 0x3b - READ_BUFFER SCSICommandType = 0x3c - UPDATE_BLOCK SCSICommandType = 0x3d - READ_LONG SCSICommandType = 0x3e - WRITE_LONG SCSICommandType = 0x3f - CHANGE_DEFINITION SCSICommandType = 0x40 - WRITE_SAME SCSICommandType = 0x41 - UNMAP SCSICommandType = 0x42 - READ_TOC SCSICommandType = 0x43 - GET_CONFIGURATION SCSICommandType = 0x46 - LOG_SELECT SCSICommandType = 0x4c - LOG_SENSE SCSICommandType = 0x4d - READ_DISK_INFO SCSICommandType = 0x51 - READ_TRACK_INFO SCSICommandType = 0x52 - MODE_SELECT_10 SCSICommandType = 0x55 - RESERVE_10 SCSICommandType = 0x56 - RELEASE_10 SCSICommandType = 0x57 - MODE_SENSE_10 SCSICommandType = 0x5a - CLOSE_TRACK SCSICommandType = 0x5b - READ_BUFFER_CAP SCSICommandType = 0x5c - PERSISTENT_RESERVE_IN SCSICommandType = 0x5e - PERSISTENT_RESERVE_OUT SCSICommandType = 0x5f - VARLEN_CDB SCSICommandType = 0x7f - READ_16 SCSICommandType = 0x88 - COMPARE_AND_WRITE SCSICommandType = 0x89 - WRITE_16 SCSICommandType = 0x8a - ORWRITE_16 SCSICommandType = 0x8b - WRITE_VERIFY_16 SCSICommandType = 0x8e - VERIFY_16 SCSICommandType = 0x8f - PRE_FETCH_16 SCSICommandType = 0x90 - SYNCHRONIZE_CACHE_16 SCSICommandType = 0x91 - WRITE_SAME_16 SCSICommandType = 0x93 - SERVICE_ACTION_IN SCSICommandType = 0x9e - SAI_READ_CAPACITY_16 SCSICommandType = 0x10 - SAI_GET_LBA_STATUS SCSICommandType = 0x12 - REPORT_LUNS SCSICommandType = 0xa0 - MAINT_PROTOCOL_IN SCSICommandType = 0xa3 - MOVE_MEDIUM SCSICommandType = 0xa5 - EXCHANGE_MEDIUM SCSICommandType = 0xa6 - READ_12 SCSICommandType = 0xa8 - WRITE_12 SCSICommandType = 0xaa - GET_PERFORMACE SCSICommandType = 0xac - READ_DVD_STRUCTURE SCSICommandType = 0xad - WRITE_VERIFY_12 SCSICommandType = 0xae - VERIFY_12 SCSICommandType = 0xaf - SEARCH_HIGH_12 SCSICommandType = 0xb0 - SEARCH_EQUAL_12 SCSICommandType = 0xb1 - SEARCH_LOW_12 SCSICommandType = 0xb2 - READ_ELEMENT_STATUS SCSICommandType = 0xb8 - SEND_VOLUME_TAG SCSICommandType = 0xb6 - SET_STREAMING SCSICommandType = 0xb6 - SET_CD_SPEED SCSICommandType = 0xbb - WRITE_LONG_2 SCSICommandType = 0xea -) - type SCSIPRServiceAction byte type SCSIPRType byte @@ -155,15 +48,6 @@ var ( PR_TYPE_EXCLUSIVE_ACCESS_ALLREG SCSIPRType = 0x08 ) -type SCSIDataDirection int - -const ( - SCSIDataNone = iota - SCSIDataWrite - SCSIDataRead - SCSIDataBidirection -) - const ( CBD_GROUPID_0 = iota CBD_GROUPID_1 @@ -186,37 +70,6 @@ const ( CDB_GROUP7 = 0 /* vendor specific */ ) -type SCSIDataBuffer struct { - Buffer *bytes.Buffer - Length uint32 - TransferLength uint32 - Resid int32 -} - -type SCSICommand struct { - Target *SCSITarget - DeviceID uint64 - Device *SCSILu - State uint64 - Direction SCSIDataDirection - InSDBBuffer SCSIDataBuffer - OutSDBBuffer SCSIDataBuffer - // Command ITN ID - CommandITNID uint64 - Offset uint64 - TL uint32 - SCB *bytes.Buffer - SCBLength int - Lun []uint8 - Attribute int - Tag uint64 - Result int - SenseBuffer *bytes.Buffer - SenseLength uint32 - ITNexus *ITNexus - ITNexusLuInfo *ITNexusLuInfo -} - func SCSICDBGroupID(opcode byte) byte { return ((opcode >> 5) & 0x7) } diff --git a/pkg/scsi/drivers.go b/pkg/scsi/drivers.go index 61c2428..fc5ce9a 100644 --- a/pkg/scsi/drivers.go +++ b/pkg/scsi/drivers.go @@ -16,76 +16,3 @@ limitations under the License. // Target Driver Interface package scsi - -type SCSITargetDriverState int - -const ( - // just registered - SCSI_DRIVER_REGD = iota - // initialized ok - SCSI_DRIVER_INIT - // failed to initialize - SCSI_DRIVER_ERR - // exited - SCSI_DRIVER_EXIT -) - -type SCSITargetDriver struct { - Name string - State SCSITargetDriverState - DefaultBST string - Targets []*SCSITarget -} - -type SCSITargetDriverOps interface { - Init() error - Exit() error - - CreateTarget(target *SCSITarget) error - DestroyTarget(target *SCSITarget) error - CreatePortal(name string) error - DestroyPortal(name string) error - CreateLu(lu *SCSILu) error - - GetLu(lun uint8) (uint64, error) - CommandNotify(nid uint64, result int, cmd *SCSICommand) error -} - -type fakeSCSITargetDriver struct { - SCSITargetDriver -} - -func (fake *fakeSCSITargetDriver) Init() error { - return nil -} - -func (fake *fakeSCSITargetDriver) Exit() error { - return nil -} - -func (fake *fakeSCSITargetDriver) CreateTarget(target *SCSITarget) error { - return nil -} - -func (fake *fakeSCSITargetDriver) DestroyTarget(target *SCSITarget) error { - return nil -} - -func (fake *fakeSCSITargetDriver) CreatePortal(name string) error { - return nil -} - -func (fake *fakeSCSITargetDriver) DestroyPortal(name string) error { - return nil -} - -func (fake *fakeSCSITargetDriver) CreateLu(lu *SCSILu) error { - return nil -} - -func (fake *fakeSCSITargetDriver) GetLun(lun uint8) (uint64, error) { - return 0, nil -} -func (fake *fakeSCSITargetDriver) CommandNotify(nid uint64, result int, cmd *SCSICommand) error { - return nil -} diff --git a/pkg/scsi/lun.go b/pkg/scsi/lun.go index ce6724b..2856a32 100644 --- a/pkg/scsi/lun.go +++ b/pkg/scsi/lun.go @@ -16,58 +16,22 @@ limitations under the License. package scsi -type SCSILuPhyAttribute struct { - SCSIID string - SCSISN string - NumID uint64 - VendorID string - ProductID string - ProductRev string - VersionDesction []uint16 - // Peripheral device type - DeviceType uint - // Peripheral Qualifier - Qualifier bool - // Removable media - Removable bool - // Read Only media - Readonly bool - // Software Write Protect - SWP bool - // Use thin-provisioning for this LUN - Thinprovisioning bool - // Logical Unit online - Online bool - // Descrptor format sense data supported - SenseFormat bool - // Logical blocks per physical block exponent - Lbppbe int - // Do not update it automatically when the backing file changes - NoLbppbe int - // Lowest aligned LBA - LowestAlignedLBA int -} +import "github.com/gostor/gotgt/pkg/api" + +type SCSILuOps struct { + *api.SCSILu -type SCSILu struct { - FD int - Address uint64 - Size uint64 - Lun uint64 - Path string - BsoFlags int - BlockShift uint - ReserveID uint64 DeviceProtocol SCSIDeviceProtocol Storage *BackingStore - Target *SCSITarget - Attrs SCSILuPhyAttribute + Target *api.SCSITarget + Attrs api.SCSILuPhyAttribute // function handler for command performing and finishing PerformCommand CommandFunc - FinishCommand func(*SCSITarget, *SCSICommand) + FinishCommand func(*api.SCSITarget, *api.SCSICommand) } -func luPreventRemoval(lu *SCSILu) bool { +func luPreventRemoval(lu *api.SCSILu) bool { // TODO return false } diff --git a/pkg/scsi/sbc.go b/pkg/scsi/sbc.go index 721244f..f9caa98 100644 --- a/pkg/scsi/sbc.go +++ b/pkg/scsi/sbc.go @@ -17,96 +17,109 @@ limitations under the License. // SCSI block command processing package scsi -import "encoding/binary" +import ( + "encoding/binary" + + "github.com/gostor/gotgt/pkg/api" +) + +const ( + PR_SPECIAL = (1 << 5) + PR_WE_FA = (1 << 4) + PR_EA_FA = (1 << 3) + PR_RR_FR = (1 << 2) + PR_WE_FN = (1 << 1) + PR_EA_FN = (1 << 0) +) type SBCSCSIDeviceProtocol struct { BaseSCSIDeviceProtocol } -func (sbc *SBCSCSIDeviceProtocol) InitLu(lu *SCSILu) error { +func (sbc *SBCSCSIDeviceProtocol) InitLu(lu *api.SCSILu) error { return nil } -func (sbc *SBCSCSIDeviceProtocol) ExitLu(lu *SCSILu) error { +func (sbc *SBCSCSIDeviceProtocol) ExitLu(lu *api.SCSILu) error { return nil } -func (sbc *SBCSCSIDeviceProtocol) ConfigLu(lu *SCSILu) error { +func (sbc *SBCSCSIDeviceProtocol) ConfigLu(lu *api.SCSILu) error { return nil } -func (sbc *SBCSCSIDeviceProtocol) OnlineLu(lu *SCSILu) error { +func (sbc *SBCSCSIDeviceProtocol) OnlineLu(lu *api.SCSILu) error { return nil } -func (sbc *SBCSCSIDeviceProtocol) OfflineLu(lu *SCSILu) error { +func (sbc *SBCSCSIDeviceProtocol) OfflineLu(lu *api.SCSILu) error { return nil } func NewSBCDevice() SBCSCSIDeviceProtocol { var sbc = SBCSCSIDeviceProtocol{ BaseSCSIDeviceProtocol{ - Type: TYPE_DISK, + Type: api.TYPE_DISK, SCSIDeviceOps: make([]SCSIDeviceOperation, 256), }, } for i := 0; i <= 256; i++ { sbc.SCSIDeviceOps = append(sbc.SCSIDeviceOps, NewSCSIDeviceOperation(SPCIllegalOp, nil, 0)) } - sbc.SCSIDeviceOps[TEST_UNIT_READY] = NewSCSIDeviceOperation(SPCTestUnit, nil, 0) - sbc.SCSIDeviceOps[REQUEST_SENSE] = NewSCSIDeviceOperation(SPCRequestSense, nil, 0) - sbc.SCSIDeviceOps[FORMAT_UNIT] = NewSCSIDeviceOperation(SBCFormatUnit, nil, 0) - sbc.SCSIDeviceOps[READ_6] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN) - sbc.SCSIDeviceOps[WRITE_6] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN|PR_WE_FA|PR_WE_FN) - sbc.SCSIDeviceOps[INQUIRY] = NewSCSIDeviceOperation(SPCInquiry, nil, 0) - sbc.SCSIDeviceOps[MODE_SELECT] = NewSCSIDeviceOperation(SBCModeSelect, nil, PR_WE_FA|PR_EA_FA|PR_WE_FN|PR_EA_FN) - sbc.SCSIDeviceOps[RESERVE] = NewSCSIDeviceOperation(SBCReserve, nil, 0) - sbc.SCSIDeviceOps[RELEASE] = NewSCSIDeviceOperation(SBCRelease, nil, 0) + sbc.SCSIDeviceOps[api.TEST_UNIT_READY] = NewSCSIDeviceOperation(SPCTestUnit, nil, 0) + sbc.SCSIDeviceOps[api.REQUEST_SENSE] = NewSCSIDeviceOperation(SPCRequestSense, nil, 0) + sbc.SCSIDeviceOps[api.FORMAT_UNIT] = NewSCSIDeviceOperation(SBCFormatUnit, nil, 0) + sbc.SCSIDeviceOps[api.READ_6] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN) + sbc.SCSIDeviceOps[api.WRITE_6] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN|PR_WE_FA|PR_WE_FN) + sbc.SCSIDeviceOps[api.INQUIRY] = NewSCSIDeviceOperation(SPCInquiry, nil, 0) + sbc.SCSIDeviceOps[api.MODE_SELECT] = NewSCSIDeviceOperation(SBCModeSelect, nil, PR_WE_FA|PR_EA_FA|PR_WE_FN|PR_EA_FN) + sbc.SCSIDeviceOps[api.RESERVE] = NewSCSIDeviceOperation(SBCReserve, nil, 0) + sbc.SCSIDeviceOps[api.RELEASE] = NewSCSIDeviceOperation(SBCRelease, nil, 0) - sbc.SCSIDeviceOps[MODE_SENSE] = NewSCSIDeviceOperation(SBCModeSense, nil, PR_WE_FA|PR_EA_FA|PR_EA_FN|PR_WE_FN) - sbc.SCSIDeviceOps[START_STOP] = NewSCSIDeviceOperation(SPCStartStop, nil, PR_SPECIAL) - sbc.SCSIDeviceOps[SEND_DIAGNOSTIC] = NewSCSIDeviceOperation(SPCSendDiagnostics, nil, 0) + sbc.SCSIDeviceOps[api.MODE_SENSE] = NewSCSIDeviceOperation(SBCModeSense, nil, PR_WE_FA|PR_EA_FA|PR_EA_FN|PR_WE_FN) + sbc.SCSIDeviceOps[api.START_STOP] = NewSCSIDeviceOperation(SPCStartStop, nil, PR_SPECIAL) + sbc.SCSIDeviceOps[api.SEND_DIAGNOSTIC] = NewSCSIDeviceOperation(SPCSendDiagnostics, nil, 0) - sbc.SCSIDeviceOps[ALLOW_MEDIUM_REMOVAL] = NewSCSIDeviceOperation(SPCPreventAllowMediaRemoval, nil, 0) - sbc.SCSIDeviceOps[READ_CAPACITY] = NewSCSIDeviceOperation(SBCReadCapacity, nil, 0) - sbc.SCSIDeviceOps[READ_10] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN) - sbc.SCSIDeviceOps[WRITE_10] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_WE_FA|PR_EA_FA|PR_EA_FN|PR_WE_FN) - sbc.SCSIDeviceOps[WRITE_VERIFY] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN) - sbc.SCSIDeviceOps[VERIFY_10] = NewSCSIDeviceOperation(SBCVerify, nil, PR_EA_FA|PR_EA_FN) + sbc.SCSIDeviceOps[api.ALLOW_MEDIUM_REMOVAL] = NewSCSIDeviceOperation(SPCPreventAllowMediaRemoval, nil, 0) + sbc.SCSIDeviceOps[api.READ_CAPACITY] = NewSCSIDeviceOperation(SBCReadCapacity, nil, 0) + sbc.SCSIDeviceOps[api.READ_10] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN) + sbc.SCSIDeviceOps[api.WRITE_10] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_WE_FA|PR_EA_FA|PR_EA_FN|PR_WE_FN) + sbc.SCSIDeviceOps[api.WRITE_VERIFY] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN) + sbc.SCSIDeviceOps[api.VERIFY_10] = NewSCSIDeviceOperation(SBCVerify, nil, PR_EA_FA|PR_EA_FN) - sbc.SCSIDeviceOps[PRE_FETCH_10] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN) - sbc.SCSIDeviceOps[SYNCHRONIZE_CACHE] = NewSCSIDeviceOperation(SBCSyncCache, nil, PR_WE_FA|PR_EA_FA|PR_WE_FN|PR_EA_FN) + sbc.SCSIDeviceOps[api.PRE_FETCH_10] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN) + sbc.SCSIDeviceOps[api.SYNCHRONIZE_CACHE] = NewSCSIDeviceOperation(SBCSyncCache, nil, PR_WE_FA|PR_EA_FA|PR_WE_FN|PR_EA_FN) - sbc.SCSIDeviceOps[WRITE_SAME] = NewSCSIDeviceOperation(SBCReadWrite, nil, 0) - sbc.SCSIDeviceOps[UNMAP] = NewSCSIDeviceOperation(SBCUnmap, nil, 0) + sbc.SCSIDeviceOps[api.WRITE_SAME] = NewSCSIDeviceOperation(SBCReadWrite, nil, 0) + sbc.SCSIDeviceOps[api.UNMAP] = NewSCSIDeviceOperation(SBCUnmap, nil, 0) - sbc.SCSIDeviceOps[MODE_SELECT_10] = NewSCSIDeviceOperation(SBCModeSelect, nil, PR_WE_FA|PR_EA_FA|PR_EA_FN|PR_WE_FN) - sbc.SCSIDeviceOps[MODE_SENSE_10] = NewSCSIDeviceOperation(SBCModeSense, nil, PR_WE_FA|PR_WE_FN|PR_EA_FA|PR_EA_FN) - sbc.SCSIDeviceOps[PERSISTENT_RESERVE_IN] = NewSCSIDeviceOperation(SPCServiceAction, nil, 0) - sbc.SCSIDeviceOps[PERSISTENT_RESERVE_OUT] = NewSCSIDeviceOperation(SPCServiceAction, nil, 0) + sbc.SCSIDeviceOps[api.MODE_SELECT_10] = NewSCSIDeviceOperation(SBCModeSelect, nil, PR_WE_FA|PR_EA_FA|PR_EA_FN|PR_WE_FN) + sbc.SCSIDeviceOps[api.MODE_SENSE_10] = NewSCSIDeviceOperation(SBCModeSense, nil, PR_WE_FA|PR_WE_FN|PR_EA_FA|PR_EA_FN) + sbc.SCSIDeviceOps[api.PERSISTENT_RESERVE_IN] = NewSCSIDeviceOperation(SPCServiceAction, nil, 0) + sbc.SCSIDeviceOps[api.PERSISTENT_RESERVE_OUT] = NewSCSIDeviceOperation(SPCServiceAction, nil, 0) - sbc.SCSIDeviceOps[READ_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN) - sbc.SCSIDeviceOps[WRITE_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN|PR_WE_FA|PR_WE_FN) - sbc.SCSIDeviceOps[ORWRITE_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN) - sbc.SCSIDeviceOps[WRITE_VERIFY_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN) - sbc.SCSIDeviceOps[VERIFY_16] = NewSCSIDeviceOperation(SBCVerify, nil, PR_EA_FA|PR_EA_FN) + sbc.SCSIDeviceOps[api.READ_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN) + sbc.SCSIDeviceOps[api.WRITE_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN|PR_WE_FA|PR_WE_FN) + sbc.SCSIDeviceOps[api.ORWRITE_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN) + sbc.SCSIDeviceOps[api.WRITE_VERIFY_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN) + sbc.SCSIDeviceOps[api.VERIFY_16] = NewSCSIDeviceOperation(SBCVerify, nil, PR_EA_FA|PR_EA_FN) - sbc.SCSIDeviceOps[PRE_FETCH_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN) - sbc.SCSIDeviceOps[SYNCHRONIZE_CACHE_16] = NewSCSIDeviceOperation(SBCSyncCache, nil, PR_EA_FA|PR_EA_FN|PR_WE_FA|PR_WE_FN) - sbc.SCSIDeviceOps[WRITE_SAME_16] = NewSCSIDeviceOperation(SBCReadWrite, nil, 0) - sbc.SCSIDeviceOps[SERVICE_ACTION_IN] = NewSCSIDeviceOperation(SPCServiceAction, nil, 0) + 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[REPORT_LUNS] = NewSCSIDeviceOperation(SPCReportLuns, nil, 0) - sbc.SCSIDeviceOps[EXCHANGE_MEDIUM] = NewSCSIDeviceOperation(SPCServiceAction, nil, 0) - sbc.SCSIDeviceOps[READ_12] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN) - sbc.SCSIDeviceOps[WRITE_12] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_WE_FA|PR_EA_FA|PR_WE_FA|PR_WE_FN) - sbc.SCSIDeviceOps[WRITE_VERIFY_12] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN) - sbc.SCSIDeviceOps[VERIFY_12] = NewSCSIDeviceOperation(SBCVerify, nil, PR_EA_FA|PR_EA_FN) + sbc.SCSIDeviceOps[api.REPORT_LUNS] = NewSCSIDeviceOperation(SPCReportLuns, 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) + sbc.SCSIDeviceOps[api.WRITE_VERIFY_12] = NewSCSIDeviceOperation(SBCReadWrite, nil, PR_EA_FA|PR_EA_FN) + sbc.SCSIDeviceOps[api.VERIFY_12] = NewSCSIDeviceOperation(SBCVerify, nil, PR_EA_FA|PR_EA_FN) return sbc } -func SBCModeSelect(host int, cmd *SCSICommand) SAMStat { - return SAMStatGood +func SBCModeSelect(host int, cmd *api.SCSICommand) api.SAMStat { + return api.SAMStatGood } -func SBCModeSense(host int, cmd *SCSICommand) SAMStat { +func SBCModeSense(host int, cmd *api.SCSICommand) api.SAMStat { // DPOFUA = 0x10 var deviceSpecific uint8 = 0x10 @@ -129,7 +142,7 @@ func SBCModeSense(host int, cmd *SCSICommand) SAMStat { data.WriteByte(deviceSpecific) } - return SAMStatGood + return api.SAMStatGood } // The FORMAT UNIT command requests that the device server format the medium into application client @@ -137,14 +150,14 @@ func SBCModeSense(host int, cmd *SCSICommand) SAMStat { // in the last mode parameter block descriptor in a MODE SELECT command (see SPC-3). In addition, // the device server may certify the medium and create control structures for the management of the medium and defects. // The degree that the medium is altered by this command is vendor-specific. -func SBCFormatUnit(host int, cmd *SCSICommand) SAMStat { +func SBCFormatUnit(host int, cmd *api.SCSICommand) api.SAMStat { var ( key = ILLEGAL_REQUEST asc = ASC_INVALID_FIELD_IN_CDB ) if err := deviceReserve(cmd); err != nil { - return SAMStatReservationConflict + return api.SAMStatReservationConflict } if !cmd.Device.Attrs.Online { @@ -172,33 +185,33 @@ func SBCFormatUnit(host int, cmd *SCSICommand) SAMStat { goto sense } - return SAMStatGood + return api.SAMStatGood sense: BuildSenseData(cmd, key, asc) - return SAMStatCheckCondition + return api.SAMStatCheckCondition } -func SBCUnmap(host int, cmd *SCSICommand) SAMStat { - return SAMStatGood +func SBCUnmap(host int, cmd *api.SCSICommand) api.SAMStat { + return api.SAMStatGood } -func SBCReadWrite(host int, cmd *SCSICommand) SAMStat { - return SAMStatGood +func SBCReadWrite(host int, cmd *api.SCSICommand) api.SAMStat { + return api.SAMStatGood } -func SBCReserve(host int, cmd *SCSICommand) SAMStat { +func SBCReserve(host int, cmd *api.SCSICommand) api.SAMStat { if err := deviceReserve(cmd); err != nil { - return SAMStatReservationConflict + return api.SAMStatReservationConflict } - return SAMStatGood + return api.SAMStatGood } -func SBCRelease(host int, cmd *SCSICommand) SAMStat { +func SBCRelease(host int, cmd *api.SCSICommand) api.SAMStat { if err := deviceRelease(cmd.Target.TID, cmd.CommandITNID, cmd.Device.Lun, false); err != nil { - return SAMStatReservationConflict + return api.SAMStatReservationConflict } - return SAMStatGood + return api.SAMStatGood } // The READ CAPACITY (10) command requests that the device server transfer 8 bytes of parameter data @@ -206,7 +219,7 @@ func SBCRelease(host int, cmd *SCSICommand) SAMStat { // This command may be processed as if it has a HEAD OF QUEUE task attribute. If the logical unit supports // protection information, the application client should use the READ CAPACITY (16) command instead of // the READ CAPACITY (10) command. -func SBCReadCapacity(host int, cmd *SCSICommand) SAMStat { +func SBCReadCapacity(host int, cmd *api.SCSICommand) api.SAMStat { var ( scb = cmd.SCB.Bytes() key = ILLEGAL_REQUEST @@ -242,15 +255,15 @@ func SBCReadCapacity(host int, cmd *SCSICommand) SAMStat { binary.Write(data, binary.BigEndian, uint32(1< Date: Tue, 3 May 2016 08:57:13 +0800 Subject: [PATCH 3/3] update README --- README.md | 93 ++++++++++++++++++++----------------------------------- 1 file changed, 33 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index 607df2b..2fb289d 100644 --- a/README.md +++ b/README.md @@ -2,65 +2,38 @@ Cloud Integrated SCSI Target framework, this includes two binaries, one is `citadm` which is command line to config and control, the other is `citd` which is a target daemon. -``` -# citadm --help -Linux SCSI Target administration utility, version 0.1 -Usage: ./citadm [OPTIONS] - -Application Options: - --lld --mode target --op new --tid --targetname - add a new target with and . must not be zero. - --lld --mode target --op delete [--force] --tid - delete the specific target with . - With force option, the specific target is deleted - even if there is an activity. - --lld --mode target --op show - show all the targets. - --lld --mode target --op show --tid - show the specific target's parameters. - --lld --mode target --op update --tid --name --value - change the target parameters of the target with . - --lld --mode target --op bind --tid --initiator-address
- --lld --mode target --op bind --tid --initiator-name - enable the target to accept the specific initiators. - --lld --mode target --op unbind --tid --initiator-address
- --lld --mode target --op unbind --tid --initiator-name - disable the specific permitted initiators. - --lld --mode logicalunit --op new --tid --lun - --backing-store --bstype --bsopts --bsoflags - add a new logical unit with to the specific - target with . The logical unit is offered - to the initiators. must be block device files - (including LVM and RAID devices) or regular files. - bstype option is optional. - bsopts are specific to the bstype. - bsoflags supported options are sync and direct - (sync:direct for both). - --lld --mode logicalunit --op delete --tid --lun - delete the specific logical unit with that - the target with has. - --lld --mode account --op new --user --password - add a new account with and . - --lld --mode account --op delete --user - delete the specific account having . - --lld --mode account --op bind --tid --user [--outgoing] - add the specific account having to - the specific target with . - could be or . - If you use --outgoing option, the account will - be added as an outgoing account. - --lld --mode account --op unbind --tid --user [--outgoing] - delete the specific account having from specific - target. The --outgoing option must be added if you - delete an outgoing account. - --lld --mode lld --op start - Start the specified lld without restarting the tgtd process. - --control-port use control port - -Help Options: - --help - display this help and exit - -Report bugs via . +## Build ``` +$ mkdir $GOPATH/gotstor/ +$ cd $GOPATH/gostor/ +$ git clone https://github.com/gostor/gotgt gotgt +$ cd gotgt +$ make +``` + +## Test + +You can test this with [libiscsi](https://github.com/gostor/libiscsi). + +### build the test tool of libiscsi + +``` +$ git clone https://github.com/gostor/libiscsi +$ cd libiscsi +$ ./autogen.sh +$ ./configure +$ make +``` + +### start the gotgt daemon + +``` +$ ./citd +``` + +### begin the test + +``` +$ ./iscsi-test-cu -v iscsi://127.0.0.1:3260/iqn.test.haha/0 +```