SCSI SAS 1275 Binding Title: Version 1.0 1 Introduction 1.1 Overview and References This document describes the application of Open Firmware to the SCSI-3 protocol as implemented on serial attached SCSI (SAS). 2 References and Definitions 2.1 References [1] IEEE Standard 1275-1994 IEEE Standard for Boot (Initialization and Configuration) Firmware: Core Requirements and Practices [2] Device Support Extensions to IEEE 1274-1994, Revision 1.0 [3] FWARC 2005/751, SAS WWID determined from system MAC address [4] FWARC 2006/035, LSI SAS Controller Methods for Manufacturing and Service [5] PCI Bus Binding to: IEEE Std 1275-1994 Standard for Boot Firmware Rev. 2.1 http://noho.eng/1275/bindings/pci/pci2_1.pdf [6] FWARC 2003/637, PCI Express Bus Binding to IEEE 1275 [7] SCSI Architecture Model-4 http://t10.org/ftp/t10/drafts/sam4/sam4r13.pdf [8] FWARC 2008/070, OBP Deblocker Package Changes for Large Disks 2.2 Definition of Terms bus node: an Open Firmware device node that represents a bus controller. In cases where a node represents the interface, or "bridge", between one bus and another, the node is both a bus node relative to the bus it controls and a child node of its parent bus. Note that an Open Firmware device node is not in itself a physical hardware device, rather it is a software abstraction that describes a hardware device. child node: A device node that represents a SAS "target" device. logical unit: A target resident entity that implements a device model and executes SCSI commands sent by an application client. phy: The hardware that drives one end of a single SAS or SATA serial link. phy identifier: A numerical identifier in the range of 0 through 0x7f used by a SAS controller, expander or device to identify a specific phy. SASAddress: 64-bit globally name unique identifier. The following SAS formats use the IEEE company identifer as the direct or indirect basis for their unique values. 3 Bus Charactistics Serial Attached SCSI (SAS) is a single standard composed of many parts. It mandates support for both SAS devices and Serial AT Attached (SATA) devices. Basic addressing in a SAS fabric is through a SASAddress. A SASAddress is a 64-bit identifier unique within a SAS domain. Native SAS devices have at least one globally unique SASAddress assigned to them, usually at the time of manufacture. Packets are routed through the SAS fabric based on either the full SASAddress or a derived 16-bit hashed SASAddress. SATA devices are designed to operate in a point-to-point configuration. They often have no associated unique identification. When operating within a SAS domain, SATA devices are managed by a SATA Transport Protocol (STP) to SATA bridge which has a SASAddress and forwards commands across the serial link to the SATA device. The STP/SATA bridge can reside within a SAS expander, SAS HBA, or the operating system driver. The STP/SATA bridge is responsible for providing a unique SASAddress for the SATA device it is managing. 3.1 Physical Address Formats and Representations The native address for a SAS domain is the SASAddress. However, SATA devices directly attached to a HBA may not have a SASAddress assigned, so a second form of addressing describes a device by the phy instance to which it is attached. It may be desirable to describe a SAS device by where it is directly attached to the adapter, hence the phy instance form of the address may be used. A driver conformant to this specification mmust be able to handle both physical address formats and is free to translate from one to the other. 3.1.1 Physical Address Formats 3.1.1.1 Numerical Representation The numerical representation of a "scsi-sas" address consists of four cells and has two possible encodings. The first form describes a 64-bit SASAddress, which can be used to describe any device within a SAS domain. The second form is only useable for directly attached devices and describes the local phy identifier used to communicate to the device. 3.1.1.1.1 SASAddress Representation This form describes device by its SASAddress. Bit#0 refers to the least significant bit. Bit # 33222222 22221111 11111100 00000000 10987654 32109876 54321098 76543210 sas.hi cell: ssssssss ssssssss ssssssss ssssssss sas.lo cell: ssssssss ssssssss ssssssss ssssssss lun.hi cell: llllllll llllllll llllllll llllllll lun.lo cell: llllllll llllllll llllllll llllllll where: ss..ss 64-bit unsigned number SASAddress ll..ll 64-bit unsigned number logical unit number 3.1.1.1.2 Phy Identifier Representation This representation identifies a phy on the SAS adapter. Bit#0 refers to the least significant bit. Bit # 33222222 22221111 11111100 00000000 10987654 32109876 54321098 76543210 sas.hi cell: 00000000 00000000 00000000 00000000 sas.lo cell: 00000000 00000000 00000000 0iiiiiii lun.hi cell: llllllll llllllll llllllll llllllll lun.lo cell: llllllll llllllll llllllll llllllll where: 00..00 Bits with the value zero ii..ii 7-bit unsigned number phy identifier ll..ll 64-bit unsigned number logical unit number For Phy Identifier representation: sas.hi [31-0] = 0 and, sas.lo [31-7] = 0 This can be used to distinguish between Phy Identifier and SASAddress representation. 3.1.1.2 Text Representation 3.1.1.2.1 The text representation of a SASAddress is of the following form: wNNNNNNNNNNNNNNN[,LLLLLLLLLLLLLLLL] where: w is the letter 'w' NNNNNNNNNNNNNNNN is an ASCII hexadecimal number in the range 0...FFFFFFFFFFFFFFFF LLLLLLLLLLLLLLLL is an ASCII hexadecimal number in the range 0...FFFFFFFFFFFFFFFF. This portion of the address is optional and may be omitted if zero. The correspondence between the text representation and numerical representation is as follows: wNNNNNNNNNNNNNNN,LLLLLLLLLLLLLLLL corresponds to a Node name with numerical value: ss...ss is a binary encoding of NNNNNNNNNNNNNNN ll...ll is a binary encoding of LLLLLLLLLLLLLLLL Conversion of hexadecimal numbers from text representation to numerical representation shall be case-insensitive and leading zeros shall be permitted but not required. Conversion from numerical representation to text representation shall use the lower case forms of the hexadecimal digits in the range a...f, suppresing leading zeros. 3.1.1.2.2 The text representation of a phy identifier is of the following form: PP[,LLLLLLLLLLLLLLLL] where: PP is an ASCII hexadecimal number in the range of 0...7F LLLLLLLLLLLLLLLL is an ASCII hexadecimal number in the range of 0...FFFFFFFFFFFFFFFF This portion of the address is optional and may be omitted if zero. The correspondence between the text representation and numerical representation is as follows: PP,LLLLLLLLLLLLLLLL corresponds to a Node name with numerical value: iiiiiii is a binary encoding of PP ll...ll is a binary encoding of LLLLLLLLLLLLLLLL Conversion of hexadecimal numbers from text representation to numerical representation shall be case-insensitive and leading zeros shall be permitted but not required. Conversion from numerical representation to text representation shall use the lower case forms of the hexadecimal digits in the range a...f, suppressing leading zeros. 4 Bus Nodes 4.1 Properties Since a SAS controller is not a root nexus and can be attached to many different bus types, the controller node needs to provide any properties or methods defined by its parent bus node. This document defines properties and methods that are specific to SAS controller nodes and their children. 4.1.1 Open Firmware-defined Properties for Bus Nodes The following standard properties, as defined in Open Firmware [1], have special meaning or interpretation for SAS: "name" Type: Prop-encoded-string Value: "scsi" "device_type" Type: Prop-encoded-string Value: "scsi-sas" "#address-cells" Type: Prop-encoded-integer Contents: Standard property name to define package's address format Value: 4 "compatible" Type: Prop-encoded-array Value: The SAS controller may be compatible with either pci or pcie devices. pci device "compatible" properties [5]: Construct a list of names in most-specific to least-specific order. The names shall be derived from values of the Vendor ID, Device ID, Subsystem Vendor ID, Subsystem ID, Revision ID and Class Code bytes, and shall have the following form, and be placed in the list in the following order: pciVVVV,DDDD.SSSS.ssss.RR (1) pciVVVV,DDDD.SSSS.ssss (2) pciSSSS,ssss (3) pciVVVV,DDDD.RR (4) pciVVVV,DDDD (5) pciclass,CCSSPP (6) pciclass,CCSS (7) Entries (1), (2) and (3) shall be included if and only if the Subsystem Vendor ID is non-zero. Entry (3) is supplied only for backwards compatiblity with versions of the PCI Binding prior to Revision 2.1; new OS binding mechanisms should instead use forms (1) or (2) to select a driver based on the values of the Subsystem Vendor ID and Subsystem ID. or pcie device "compatible" properties [6]: pciexVVVV,DDDD.SSSS.ssss.RR (1) pciexVVVV,DDDD.SSSS.ssss (2) pciexVVVV,DDDD.RR (4) pciexVVVV,DDDD (5) pciexclass,CCSSPP (6) pciexclass,CCSS (7) Note that entry (3) from the original list has been removed, since some vendors do allocate similar subsystem ID/subsystem vendor ID to different adapters with different vendor ID/device ID. where: VVVV is the Vendor ID DDDD is the Device ID SSSS is the Subsystem Vendor ID ssss is the Subsystem ID RR is the Revision ID CC is the most-significant byte of the Class Code (base class code, at 0x0b). SS is the second-most-significant byte of the Class Code (sub-class code, at 0x0a). PP is the least-significant byte of the Class Code (programming interface, at 0x09). VVVV, DDDD, SSSS, ssss and RR are lower-case ASCII hexadecimal numbers without leading zeroes. CC, SS and PP are lower-case ASCII hexadecimal numbers including leading zeroes. The following property is defined in, SAS WWID determined from system MAC address [3]: "local-wwid" Type: Prop-encoded-array Value: 64-bit base WWID address assigned to the device represented by the package containing this property 4.2 Methods 4.2.1 Open Firmware-defined Methods for Bus Nodes A Standard Package implementing the "scsi-sas" device type shall implement the following standard methods as defined in Open Firmware [1], with physical address representations as specified in 3.1 of this standard: open ( -- okay? ) Prepare this device for subsequent use. Typical behavior is to allocate any special resource requirements it needs, map the device into virtual address space, initialize the device and perform a brief "sanity test" to ensure that the device appears to be working correctly. Return true if this open method was successful, false if not. When a device's open method is called, that device's parent has already been opened (and so on, up to the root node, which has no parent), so this open method can call its parent's methods, for instance to create mappings within the parent's address space. close ( -- ) Close this previously opened device. Restore the device (which has been previously opened) to its "not-in-use" state. Typical behavior is to turn off the device, unmap it, and deallocate any resources that were allocated by open. Note: When closing an instance chain, a particular instance's close method is executed before its parents instances are closed, so the parent's methods can still be used during the execution of close. decode-unit ( addr len -- lun.lo lun.hi sas.low sas.hi ) Convert text representation of address to numerical representation The text representation can be of the SASAddress form, or the target id form. Convert unit-string (addr, len), the text string representation, to lun target, the numerical representation of a physical address within the address space defined by this device node. decode-unit is a static method. encode-unit ( lun.lo lun.hi sas.low sas.hi -- addr len ) Convert numerical representation of address to text representation The text representation that the address will be encoded to can be of the SASAddress form, or the target id form. Convert lun target, the numerical representation, to unit-string (prop-addr, prop-len), the text string representation of a physical address within the address space defined by this device node. encode-unit is a static method. dma-alloc ( size -- virt ) Allocate a memory region for later use. Allocate 'size' bytes of memory, contiguous within the direct-memory-access address space of the device bus, suitable for direct memory access by a "bus master" device. Return the virtual address 'virt'. That virtual address is suitable for CPU access to the allocated region, but, in general, dma-map-in must be used to convert it to an address suitable for direct memory access by the bus-master device. Allocate the memory according to the most stringent alignment requirements for the bus. See also: dma-map-in, dma-free If the requested operation cannot be performed, a throw shall be called with an appropriate error message, as with abort". NOTE: Out-of-memory conditions may be detected and handled properly in the code with ['] dma-alloc catch. Allocate a memory region for later use. dma-free ( virt size -- ) Free memory allocated with dma-alloc. Free 'size' bytes of memory at virtual address 'virt', previously allocated by the dma-alloc method. dma-map-in ( virt size cacheable? -- devaddr ) Convert virtual address to device bus DMA address. Convert the virtual address range , previously allocated by the dma-alloc method, into an address suitable for DMA on the device bus. Return this address 'devaddr'. dma-map-in can also be used to map application-supplied data buffers for DMA use, if possible on the bus. If the flag cacheable?, is nonzero, the caller wishes to make use of caches for the DMA buffer if they are available. Immediately after dma-map-in has been executed, the contents of the address range as seen by the processor (the processor's "view") is the same as the contents as seen by the device that performs the DMA (the device's "view"). After the DMA device has performed DMA or the processor has performed a write to the range in question, the contents of the address range as seen by the processor (the processor's "view") is not necessarily the same as the contents as seen by the device that performs the DMA (the device's "view"). The two views can be made consistent by executing dma-map-out. If the requested operation cannot be performed, a throw shall be called with an appropriate error message, as with abort". NOTE: Out-of-memory conditions may be detected and handled properly in the code with ['] dma-map-in catch. dma-map-out ( virt devaddr size -- ) Free DMA mapping set up with dma-map-in. Free the DMA mapping specified by , previously created with the dma-map-in method. This will also have the effect of flushing all caches associated with that mapping. 4.2.2 Bus-specific Methods for Bus Nodes A package implementing the "scsi-sas" device type may implement the following optional bus-specific method: max-transfer ( -- max-len ) Return size of largest possible transfer. Return the size (max-len) in bytes of the largest single transfer that this device can perform, rounded down to a multiple of block-size. set-address ( lun.lo lun.hi sas.lo sas.hi -- ) Set the SAS target and logical unit to which subsequent commands apply. set-timeout ( msecs -- ) Sets the maximum length of time in milliseconds that the driver will wait for completion of a command. The default value of zero means to wait indefinitely. A hardware error result is reported for a command that times out. show-children ( -- ) Searches the SAS for attached targets and their associated logical units. Displays the information that the SCSI inquiry reports for those devices. diagnose ( -- error-code | 0 ) Performs a simple self-test for generic SCSI device. Perform an SCSI "test-unit-ready" command on the currently selected target and unit (see set-address). If that fails, display a message indicating the details of the failure and return a non-zero error code. Otherwise, perform a SCSI "send-diagnostic" command, returning zero if it succeeds or a non-zero error code if it fails. show-sas-wwid ( -- ) The word show-sas-wwid prints the 64-bit base SAS WWID of the LSI controller in human-readable format. The precise format of the display is left to the implementation[4]. 5 Child Nodes Properties and Methods Child nodes shall implement the standard Open Firmware properties corresponding to the device type. The child nodes of SAS controllers do not have any "reg" property. SAS controllers support the attachment of disks and CDROM/DVD drives. CDROM/DVD drives will be categorized as disk devices. 5.1 DISK DEVICES 5.1.1 PROPERTIES "name" Type: Prop-encoded-string Value: "disk" "device_type" Type: Prop-encoded-string Value: "block" "compatible" Type: Prop-encoded-string Value: "sd" The following property is defined in, OBP Deblocker Package Changes for Large Disks [8]: "lba64" Type: Prop-encoded-array Value: Property contains no data. prop-encoded-array is NULL. 5.1.2 METHODS Child nodes shall implement the standard Open Firmware methods as modified by the Open Firmware Recommended Practice, Device Support Extensions [1]. Devices that can be used as boot devices share be of type "block" and shall define the following methods: The following methods are required by IEEE 1275 [1] to use the "disk-label" package: open ( -- okay? ) Prepare this device for subsequent use. Typical behavior is to allocate any special resource requirements it needs, map the device into virtual address space, initialize the device and perform a brief "sanity test" to ensure that the device appears to be working correctly. Return true if this open method was successful, false if not. When a device's open method is called, that device's parent has already been opened (and so on, up to the root node, which has no parent), so this open method can call its parent's methods, for instance to create mappings within the parent's address space. close ( -- ) Close this previously opened device Restore the device (which has been previously opened) to its "not-in-use" state. Typical behavior is to turn off the device, unmap it, and deallocate any resources that were allocated by open. Note: When closing an instance chain, a particular instance's close method is executed before its parents instances are closed, so the parent's methods can still be used during the execution of close. load ( addr -- len ) Load a client program from device to memory. Load a client program from the device into memory beginning at address addr, returning len, the size in bytes of the program that was loaded. If the device can contain several such programs, the instance-arguments (as returned by my-args) can be used in a device-dependent manner to select the particular program. Usage Restriction: The package containing the load method must be open before the load method is executed. offset ( d.rel -- d.abs ) Convert partition-relative disk position to absolute position. This is a method of the disk label support package. d.rel is a double- number disk position, expressed as the number of bytes from the beginning of the partition that was specified in the arguments when the support package was opened. d.abs is the corresponding double-number disk position, expressed as the number of bytes from the beginning of the disk. If no partition was specified when the support package was opened, a system-dependent default partition is used. If the disk label support package does not support disk partitioning, d.abs is equal to d.rel. The following methods are required by IEEE 1275 [1] to use the "deblocker" package: read ( addr len -- actual ) Read device into memory buffer; return actual byte count. Read at most len bytes from the device into the memory buffer beginning at addr. Return actual, the number of bytes actually read. If actual is zero or negative, the read operation did not succeed. Some standard device types impose additional requirements on their read methods; see the descriptions of various device types (e.g., "network" ) for more information. For some devices, the seek method sets the position for the next read. write ( addr len -- actual ) Write memory buffer to device; return actual byte count. Write len bytes to the device from the memory buffer beginning at addr. Return actual, the number of bytes actually written. If actual is less than len, the write did not succeed. For some devices, the seek method sets the position for the next write. seek ( pos.lo pos.hi -- status ) Set device position for next read or write. Set the device position at which the next read or write will take place. The position is specified by a pair of numbers pos.lo pos.hi, whose interpretation depends on the device type. Return -1 if the operation fails and either zero or one if it succeeds. NOTE- The return value one (1) is meant as a concession to existing practice. Programs that use the seek method should treat either of the status values 0 or 1 as an indication of success. block-size ( -- block-len ) Return "granularity" for accesses to this device. Return the "granularity" in bytes for accesses to this device. Perform all transfers to the device in multiples of this size. A returned value of 1 signifies that arbitrary transfer sizes are support (up to the maximum specified by max-transfer). max-transfer ( -- max-len ) Return size of largest possible transfer. Return the size in bytes of the largest single transfer that this device can perform, rounded down to a multiple of block-size. read-blocks ( addr block# #blocks -- #read ) Read #blocks, starting at block#, from device into memory. Read #blocks records of length block-size bytes from the device (starting at device block block#) into memory (starting at addr). Return #read, the number of blocks actually read. If the device is not capable of random access (e.g., a sequential access tape device), block# is ignored. write-blocks ( addr block# #blocks -- #written ) Write #blocks from memory into device, starting at block#. Write #blocks records of length block-size bytes from memory (starting at addr) to the device (starting at device block block#). Return #written, the number of blocks actually written. If the device is not capable of random access (e.g., a sequential access tape device), block# is ignored. The following methods were defined in, OBP Deblocker Package Changes for Large Disks [8]: read-blocks64 ( addr d.block# #blocks -- #read ) Read #blocks, starting at d.block#, from device into memory. Read #blocks records of length block-size bytes from the device (starting at block d.block#) into memory (starting at addr.) Return #read, the number of blocks actually read. If the device is not capable of random access (e.g., a sequential access tape device) d.block# is ignored. write-blocks64 (addr d.block# #blocks -- #written ) Write #blocks from memory into device, starting at d.block#. Write #blocks records of length block-size bytes from memory (starting at addr) to the device (starting at block number d.block#.) Return #written, the number of blocks actually written. If the device is not capable of random access (e.g., a sequential access tape device), d.block# is ignored. The following methods were defined in a proposal titled: "Additional requirements for SCSI devices": The "disk-label" standard support package and packages of device type "block" and "byte" shall implement the following method: size ( -- d ) Return as a double number "d", the number of bytes of storage associated with the device or instance. If the size cannot be determined, return the double number -1. Packages of device type "block" and "byte" shall implement the following methods: #blocks ( -- u ) Return as an unsigned number "u", the nmber of blocks of storage associated with the device or instance, where "block" is a unit of storage consisting of the number of bytes returned by the package's "block-size" method. If the size cannot be determined, or if the number of blocks exceeds the range of an unsigned number, return the maximum unsigned interger (which because of the Open Firmware's assumption of two's complement arthmetic is equivalent to the signed number -1). The "disk-label" standard support package and packages of device type "block" shall implement the following methods: offset-low ( -- u ) Return the least significant cell of the double number denoting the beginning offset of the disk partition that was specified when the "disk-label" support package was opened. In general, the offset is obtained by executing the offset method of the "disk-label" support package with an argument of zero. It is permissible for the disk package to execute the "disk-label" support package's offset method once after opening that support package, storing for later use. offset-high ( -- u ) Return the most significant cell of the double number denoting the beginning offset of the disk partition that was specified when the "disk-label" support package was opened. In general, the offset is obtained by executing the offset method of the "disk-label" support package with an argument of zero. It is permissible for the disk package to execute the "disk-label" support package's offset method once after opening that support package, storing for later use. The following method was defined in, OBP Deblocker Package Changes for Large Disks [8], and shall implemented in packages of device type "block": #blocks64 ( -- d.blocks ) Return the size of the device in blocks. Return, as a double number "d.blocks", the number of blocks of storage associated with the device or instance, where a "block" is a unit of storage consisting of the number of bytes returned by the package's "block-size" method. If the size cannot be determined, or if the number of blocks exceeds the range of a double number, return the double number -1.