311 lines
8.8 KiB
Go
311 lines
8.8 KiB
Go
/*
|
|
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.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package scsi
|
|
|
|
import (
|
|
"github.com/gostor/gotgt/pkg/util"
|
|
)
|
|
|
|
const (
|
|
// PERSISTENT_RESERVE_IN service action codes
|
|
PR_IN_READ_KEYS byte = 0x00
|
|
PR_IN_READ_RESERVATION byte = 0x01
|
|
PR_IN_REPORT_CAPABILITIES byte = 0x02
|
|
PR_IN_READ_FULL_STATUS byte = 0x03
|
|
|
|
// PERSISTENT_RESERVE_OUT service action codes
|
|
PR_OUT_REGISTER byte = 0x00
|
|
PR_OUT_RESERVE byte = 0x01
|
|
PR_OUT_RELEASE byte = 0x02
|
|
PR_OUT_CLEAR byte = 0x03
|
|
PR_OUT_PREEMPT byte = 0x04
|
|
PR_OUT_PREEMPT_AND_ABORT byte = 0x05
|
|
PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY byte = 0x06
|
|
PR_OUT_REGISTER_AND_MOVE byte = 0x07
|
|
|
|
// Persistent Reservation scope
|
|
PR_LU_SCOPE byte = 0x00
|
|
|
|
// Persistent Reservation Type Mask format
|
|
PR_TYPE_WRITE_EXCLUSIVE byte = 0x01
|
|
PR_TYPE_EXCLUSIVE_ACCESS byte = 0x03
|
|
PR_TYPE_WRITE_EXCLUSIVE_REGONLY byte = 0x05
|
|
PR_TYPE_EXCLUSIVE_ACCESS_REGONLY byte = 0x06
|
|
PR_TYPE_WRITE_EXCLUSIVE_ALLREG byte = 0x07
|
|
PR_TYPE_EXCLUSIVE_ACCESS_ALLREG byte = 0x08
|
|
)
|
|
|
|
const (
|
|
// 6-byte commands
|
|
CDB_GROUPID_0 = 6
|
|
// 10-byte commands
|
|
CDB_GROUPID_1 = 10
|
|
// 10-byte commands
|
|
CDB_GROUPID_2 = 10
|
|
// reserved
|
|
CDB_GROUPID_3 = 0
|
|
// 16-byte commands
|
|
CDB_GROUPID_4 = 16
|
|
// 12-byte commands
|
|
CDB_GROUPID_5 = 12
|
|
// vendor specific
|
|
CDB_GROUPID_6 = 0
|
|
// vendor specific
|
|
CDB_GROUPID_7 = 0
|
|
)
|
|
|
|
func SCSICDBGroupID(opcode byte) byte {
|
|
return ((opcode >> 5) & 0x7)
|
|
}
|
|
|
|
/*
|
|
* Protocol Identifier Values
|
|
*
|
|
* 0 Fibre Channel (FCP-2)
|
|
* 1 Parallel SCSI (SPI-5)
|
|
* 2 SSA (SSA-S3P)
|
|
* 3 IEEE 1394 (SBP-3)
|
|
* 4 SCSI Remote Direct Memory Access (SRP)
|
|
* 5 iSCSI
|
|
* 6 SAS Serial SCSI Protocol (SAS)
|
|
* 7 Automation/Drive Interface (ADT)
|
|
* 8 AT Attachment Interface (ATA/ATAPI-7)
|
|
*/
|
|
|
|
const (
|
|
PIV_FCP = byte(0x00)
|
|
PIV_SPI = byte(0x01)
|
|
PIV_S3P = byte(0x02)
|
|
PIV_SBP = byte(0x03)
|
|
PIV_SRP = byte(0x04)
|
|
PIV_ISCSI = byte(0x05)
|
|
PIV_SAS = byte(0x06)
|
|
PIV_ADT = byte(0x07)
|
|
PIV_ATA = byte(0x08)
|
|
PIV_USB = byte(0x09)
|
|
PIV_SOP = byte(0x0A)
|
|
)
|
|
|
|
const (
|
|
VERSION_NOT_CLAIM = byte(0x00)
|
|
VERSION_WITHDRAW_STANDARD = byte(0x03)
|
|
VERSION_WITHDRAW_SPC2 = byte(0x04)
|
|
VERSION_WITHDRAW_SPC3 = byte(0x05)
|
|
)
|
|
|
|
/*
|
|
* Code Set
|
|
*
|
|
* 1 - Designator fild contains binary values
|
|
* 2 - Designator field contains ASCII printable chars
|
|
* 3 - Designaotor field contains UTF-8
|
|
*/
|
|
const (
|
|
INQ_CODE_BIN = byte(1)
|
|
INQ_CODE_ASCII = byte(2)
|
|
INQ_CODE_UTF8 = byte(3)
|
|
)
|
|
|
|
/*
|
|
* Association field
|
|
*
|
|
* 00b - Associated with Logical Unit
|
|
* 01b - Associated with target port
|
|
* 10b - Associated with SCSI Target device
|
|
* 11b - Reserved
|
|
*/
|
|
const (
|
|
ASS_LU = byte(0x00)
|
|
ASS_TGT_PORT = byte(0x01)
|
|
ASS_TGT_DEV = byte(0x02)
|
|
)
|
|
|
|
/*
|
|
* Table 177 — PERIPHERAL QUALIFIER field
|
|
* Qualifier Description
|
|
* 000b - A peripheral device having the indicated peripheral
|
|
* device type is connected to this logical unit. If the device server is
|
|
* unable to determine whether or not a peripheral device is connected,
|
|
* then the device server also shall use this peripheral qualifier.
|
|
* This peripheral qualifier does not indicate that the peripheral
|
|
* device connected to the logical unit is ready for access.
|
|
* 001b - A peripheral device having the indicated peripheral device type
|
|
* is not connected to this logical unit. However, the device server is capable of
|
|
* supporting the indicated peripheral device type on this logical unit.
|
|
* 010b - Reserved
|
|
* 011b - The device server is not capable of supporting a
|
|
* peripheral device on this logical unit. For this peripheral
|
|
* qualifier the peripheral device type shall be set to 1Fh. All other peripheral
|
|
* device type values are reserved for this peripheral qualifier.
|
|
* 100b to 111b Vendor specific
|
|
*/
|
|
const (
|
|
PQ_DEVICE_CONNECTED = byte(0x00 << 5)
|
|
PQ_DEVICE_NOT_CONNECT = byte(0x01 << 5)
|
|
PQ_RESERVED = byte(0x02 << 5)
|
|
PQ_NOT_SUPPORT = byte(0x03 << 5)
|
|
)
|
|
|
|
const (
|
|
INQUIRY_SCCS = byte(0x80)
|
|
INQUIRY_AAC = byte(0x40)
|
|
INQUIRY_TPGS_NO = byte(0x00)
|
|
INQUIRY_TPGS_IMPLICIT = byte(0x10)
|
|
INQUIRY_TPGS_EXPLICIT = byte(0x20)
|
|
INQUIRY_TPGS_BOTH = byte(0x30)
|
|
INQUIRY_3PC = byte(0x08)
|
|
INQUIRY_Reserved = byte(0x06)
|
|
INQUIRY_PROTECT = byte(0x01)
|
|
|
|
INQUIRY_NORM_ACA = byte(0x20)
|
|
INQUIRY_HISUP = byte(0x10)
|
|
INQUIRY_STANDARD_FORMAT = byte(0x02)
|
|
|
|
INQUIRY_ENCSERV = byte(0x40)
|
|
INQUIRY_VS0 = byte(0x20)
|
|
INQUIRY_MULTIP = byte(0x10)
|
|
INQUIRY_ADDR16 = byte(0x01)
|
|
|
|
INQUIRY_WBUS16 = byte(0x20)
|
|
INQUIRY_SYNC = byte(0x10)
|
|
INQUIRY_CMDQUE = byte(0x02)
|
|
INQUIRY_VS1 = byte(0x01)
|
|
|
|
INQUIRY_QAS = byte(0x02)
|
|
INQUIRY_IUS = byte(0x01)
|
|
)
|
|
|
|
const (
|
|
ADDRESS_METHOD_PERIPHERAL_DEVICE = byte(0x00)
|
|
ADDRESS_METHOD_FLAT_SPACE = byte(0x01)
|
|
ADDRESS_METHOD_LOGICAL_UNIT = byte(0x02)
|
|
ADDRESS_METHOD_EXTENDED_LOGICAL_UNIT = byte(0x03)
|
|
)
|
|
|
|
/*
|
|
* Designator type - SPC-4 Reference
|
|
*
|
|
* 0 - Vendor specific - 7.6.3.3
|
|
* 1 - T10 vendor ID - 7.6.3.4
|
|
* 2 - EUI-64 - 7.6.3.5
|
|
* 3 - NAA - 7.6.3.6
|
|
* 4 - Relative Target port identifier - 7.6.3.7
|
|
* 5 - Target Port group - 7.6.3.8
|
|
* 6 - Logical Unit group - 7.6.3.9
|
|
* 7 - MD5 logical unit identifier - 7.6.3.10
|
|
* 8 - SCSI name string - 7.6.3.11
|
|
*/
|
|
const (
|
|
DESG_VENDOR = iota
|
|
DESG_T10
|
|
DESG_EUI64
|
|
DESG_NAA
|
|
DESG_REL_TGT_PORT
|
|
DESG_TGT_PORT_GRP
|
|
DESG_LU_GRP
|
|
DESG_MD5
|
|
DESG_SCSI
|
|
)
|
|
|
|
const (
|
|
NAA_IEEE_EXTD = byte(0x2)
|
|
NAA_LOCAL = byte(0x3)
|
|
NAA_IEEE_REGD = byte(0x5)
|
|
NAA_IEEE_REGD_EXTD = byte(0x6)
|
|
)
|
|
|
|
var (
|
|
SCSIVendorID = "GOSTOR"
|
|
SCSIProductID = "GOTGT"
|
|
SCSIID = "iqn.2016-09.com.gotgt.gostor:iscsi-tgt"
|
|
)
|
|
|
|
/*
|
|
* Transfer Length (if any)
|
|
* Parameter List Length (if any)
|
|
* Allocation Length (if any)
|
|
*/
|
|
func SCSICDBBufXLength(scb []byte) (int64, bool) {
|
|
var (
|
|
opcode byte
|
|
length int64
|
|
group byte
|
|
ok bool = true
|
|
)
|
|
opcode = scb[0]
|
|
group = SCSICDBGroupID(opcode)
|
|
|
|
// Note: group is 0-7, not the CDB length (6, 10, 12, 16)
|
|
switch group {
|
|
case 0: // GROUPID_0: 6-byte commands
|
|
// INQUIRY (0x12) and REQUEST_SENSE (0x03) have Allocation Length in bytes 3-4
|
|
if opcode == 0x12 || opcode == 0x03 {
|
|
length = int64(util.GetUnalignedUint16(scb[3:5]))
|
|
} else {
|
|
// For other Group 0 commands (READ_6, WRITE_6, etc.),
|
|
// byte 4 is typically Transfer Length, not Allocation Length.
|
|
// We should not use it to limit sense data buffer.
|
|
ok = false
|
|
}
|
|
case 1, 2: // GROUPID_1, GROUPID_2: 10-byte commands
|
|
// PERSISTENT_RESERVE_IN (0x5E) and PERSISTENT_RESERVE_OUT (0x5F)
|
|
// have Allocation Length in bytes 6-7, not 7-8
|
|
if opcode == 0x5E || opcode == 0x5F {
|
|
// Manual BigEndian conversion for PRIN/PROUT
|
|
length = int64(uint16(scb[6])<<8 | uint16(scb[7]))
|
|
} else if opcode == 0x28 || opcode == 0x2A || opcode == 0x2E || opcode == 0x35 ||
|
|
opcode == 0x34 || opcode == 0x2F || opcode == 0x41 || opcode == 0x55 ||
|
|
opcode == 0x5A || opcode == 0x56 || opcode == 0x57 {
|
|
// READ_10(0x28), WRITE_10(0x2A), WRITE_VERIFY(0x2E), SYNCHRONIZE_CACHE(0x35),
|
|
// PRE_FETCH_10(0x34), VERIFY_10(0x2F), WRITE_SAME(0x41), MODE_SELECT_10(0x55),
|
|
// MODE_SENSE_10(0x5A), RESERVE_10(0x56), RELEASE_10(0x57)
|
|
// These commands have Transfer Length or Parameter List Length in bytes 7-8,
|
|
// not Allocation Length.
|
|
ok = false
|
|
} else {
|
|
length = int64(util.GetUnalignedUint16(scb[7:9]))
|
|
}
|
|
case 3: // GROUPID_3: variable length
|
|
if opcode == 0x7F {
|
|
length = int64(scb[7])
|
|
} else {
|
|
ok = false
|
|
}
|
|
case 4: // GROUPID_4: 16-byte commands
|
|
// READ_16(0x88), WRITE_16(0x8A), WRITE_VERIFY_16(0x8E), SYNCHRONIZE_CACHE_16(0x91),
|
|
// PRE_FETCH_16(0x90), VERIFY_16(0x8F), WRITE_SAME_16(0x93), ORWRITE_16(0x8B)
|
|
if opcode == 0x88 || opcode == 0x8A || opcode == 0x8E || opcode == 0x91 ||
|
|
opcode == 0x90 || opcode == 0x8F || opcode == 0x93 || opcode == 0x8B {
|
|
// These commands have Transfer Length in bytes 6-9, not Allocation Length
|
|
ok = false
|
|
} else {
|
|
length = int64(util.GetUnalignedUint32(scb[6:10]))
|
|
}
|
|
case 5: // GROUPID_5: 12-byte commands
|
|
// READ_12(0xA8), WRITE_12(0xAA), WRITE_VERIFY_12(0xAE), VERIFY_12(0xAF)
|
|
if opcode == 0xA8 || opcode == 0xAA || opcode == 0xAE || opcode == 0xAF {
|
|
// These commands have Transfer Length in bytes 10-13, not Allocation Length
|
|
ok = false
|
|
} else {
|
|
length = int64(util.GetUnalignedUint32(scb[10:14]))
|
|
}
|
|
default:
|
|
ok = false
|
|
}
|
|
return length, ok
|
|
}
|