SDcard Stack Phase I Functional Specification Garrett D'Amore (gdamore@sun.com) Nov 28, 2007 CHAPTER 1: Introduction ======================== One of the most popular of a growing number of digital memory formats is the Secure Digital (SD for short) family. This format is used by many modern cameras, MP3 players, and readers are readily found in USB readers and on-board slots on mobile computing devices. SD is an evolution of MultiMediaCard (MMC), and generally all SD readers can read MMC media. (Newer media versions of the MMC have evolved, and it is not clear at this time that MMC/SD compatibility has been retained, although it is quite likely that at least some form of electrical compatibility has been retained with only a need for software changes.) The latest SD standard also supports high capacity (>2GB) media, and includes support for general purpose I/O devices such as 802.11 adapters, bluetooth, and even digital cameras. SD itself specifies a bus with either one or four data pins, and some additional control pins. All SD cards can also be used on Serial Peripheral Interface busses, although such interfaces are not commonly found on consumer grade equipment. (SPI is much too slow for many of the applications for which SD technology is usually deployed.) Note that most (all?) USB readers act as translators for SD memory cards, making thhem appear as USB mass storage devices. Thus such readers can normally only use memory cards. CHAPTER 2: SDcard Stack Long Term ================================== Our long term view is to provide a general purpose SD stack (SDA, for SD Architecture), with public APIs for SD host drivers, as well as target devices for I/O peripherals. As part of that view, we would supply a reference host driver implementation for the most common "standard" host controller (SD Standard Host Controller, identified by PCI class 0x8 and subclass 0x5.) This is the standard implemented by the controllers found on most modern laptops. We would also supply a driver for the memory cards (which will not use the same APIs as generic SD I/O peripherals, due to the very different nature of how such devices interact with the bus) and one additional I/O peripheral yet to be determined. CHAPTER 3: SDcard Stack Near Term ================================== We desire to get some experience with SD and get the most needed functionality to market quickly - namely support for memory cards in slots found on the most common laptop models. To that end, we propose to deliver a simplified SD stack, with only the following components: * sda - core framework * sdhost - host driver for SD Standard Host Controller * sdcard - SD memory card driver, more below For this delivery, which we will term Phase I, we would make the nexus driver APIs Consolidation Private. The API between the sdcard and sda modules will always be Project Private. Later, in Phase II, we would open up the host driver API and add leaf driver APIs. This PSARC case only addresses Phase I. The sdcard driver will make use of (or logically appear to do so, more below) the blk2scsa project to appear as a SCSI-2 device with removable media. This will allow SD memory media to participate fully in Solaris, including support for hot insertion and removal, just like when they are used in USB readers. The sdcard driver itself will actually have only a tiny amount of code in it, as instead the sda module will provide all of the core functionality needed, including implementing the needed blk2scsa operations. This is being done to reduce overhead and complexity that would be caused by a "true" layered approach. The reason that the sdcard driver exists at all (rather than allowing sda host drivers to act as blk2scsa drivers themselves) is that in the future we anticipate needing to export different nexus operations for SDA I/O peripherals. Since a given device info can only have one set of nexus operations (bus_ops), an additional placeholder is required to avoid conflict. Here's a picture of what the architecture will look like in Phase I. +--------------+ | pcfs mounted | +--------------------+ | filesystem | | sda common module | +--------------+ +--------------+ +--------------+ ^ | sda host |------------| sda memory | | +-- | driver API | | card private | +----------+ | +--------------+ +--- | API +----------+ | sd | | sdhost | | +-----------| blk2scsa | --> | emulated | | host | +-------+ | sdcard | +----------+ | target 0 | | driver | -> | SD | -> | driver | +----------+ | | | slot | | | +--------+ | (bus) | +----------+ ^ +-------+ | +---------+ | PCI bus | +---------+ CHAPTER 4: Memory Card API (Phase I) ===================================== The sda module provides only two functions for the sdcard driver: int sda_mem_init(struct modlinkage *); int sda_mem_fini(struct modlinkage *); The sdcard driver needs only to call these in its _init(9e) and _fini(9e) entry points. The sdcard driver will supply an unpopulated dev_ops in its modlinkage. The sda module will populate the dev_ops, including attach, detach, cb_ops, and any other required supporting functions. CHAPTER 5: Host Driver API (Phase I) ====================================== The host driver API is quite a bit more complex. It is provided in the header file, as follows. 5.1 Types --------- The host driver API includes the following types. typedef struct sda_host sda_host; An opaque (to the host driver) handle to the framework's state for the host. There will be one of these per host driver instance. typedef struct sda_cmd sda_cmd_t; This is structure represents a command to be sent to the SD card. The SD Simplified Physical Layer Specification[1] outlines some of them. It has the following members: uint8_t sc_index; The "index", or operation code, for the command. E.g. the GO_IDLE command is 0, the APP_CMD command is 55, etc. uint32_t sc_argument; The command-specific argument for the command. uint8_t sc_rtype; The response type expected. It will be one of R1, R1b, R2, R3, R4, R5, R5b, R6, or R7. uint32_t sc_response[4]; The response data from the command. For R2, the 8-bit prefix is removed, and the remaining words are stored in native byte order. For all other response types the 8-bit prefix and 8-bit suffix are removed, and the remaining 32-bits are stored in native order in sc_response[0]. This field is supplied by the host driver. uint16_t sc_nblks; For commands with a data transfer phase, this is the number of SD protocol blocks to transfer. See sc_blksz below for more detail. uint16_t sc_blksz; SD uses a blocking factor. This is the block size to use. (Stream oriented commands can use a value of 1 here.) Memory commands will generally use 512 or the native card block size here. uint32_t sc_resid; Upon completion, the host driver should indicate any residual number of bytes that were not transferred here. caddr_t sc_kvaddr; If non-zero, then this is the starting address of a kernel buffer for the data transfer. uint_t sc_ndmac; ddi_dma_cookie_t *sc_dmacs; If sc_ndmac is non-zero, then the buffer has been prepared for DMA already, and cookies to use are supplied here. uint32_t sc_flags; Flags for the operation. SDA_CMDF_READ and SDA_CMDF_WRITE indicate the direction of any data transfer. SDA_CMDF_AUTO_CMD12 indicates that a multi-block operation requires a CMD12 to terminate the transfer when the transfer is complete. SDA_CMDF_POLLED indicates that polled I/O should be used to complete the transfer, in which case the xxx_cmd() entry point in the host driver won't return until the command has completed. typedef struct sda_ops sda_ops_t; This structure is the operations vector implemented by the host driver. It contains the following members. int so_version; Must be set to SDA_OPS_VERSION for Phase I. int (*so_cmd)(void *private, sda_cmd_t *); This is the main submission entry point for SD commands. The private argument is the host driver's private data handle that was established for the slot. Unless the command has SDA_CMDF_POLLED set, the host driver will return immediately. Returns 0 on success, an errno otherwise. int (*so_getprop)(void *private, int propnum, uint32_t *valp); int (*so_setprop)(void *private, int propnum, uint32_t val); These two functions are used to access bus control properties for the host. The following properties are defined: SDA_PROP_INSERTED - 1 if a card is prsent in the slot, 0 otherwise SDA_PROP_WPROTECT - 1 if the card has a write protect tab enabled, 0 otherwise. SDA_PROP_LED - set to 1 to turn an access LED on, 0 to turn off. SDA_PROP_CLOCK - change the bus speed, argument is given in Hz. SDA_PROP_BUSWIDTH - set to change the bus width on the controller, argument is eitehr 1 or 4. SDA_PROP_OCR - the bit mask of voltages for the slot. On read returns the set supported by the slot. On write, a single bit (only) sets the voltage for the slot. See [1] for more detail on the specific bits. (sda.h defines values OCR_35_36V, OCR_34_35V... OCR_17_18V for this purpose. The other OCR bits (power up bit, CCS, number of functions for IO cards) are not used with this property. SDA_PROP_CAP_4BITS - reads as true if the slot supports 4-bit bus SDA_PROP_CAP_HIV - indicates the slot can operate between 2.7 and 3.6 volts. SDA_PROP_CAP_NOPIO - indicates that the host never needs to access kernel virtual memory associated with transfer buffers if the DMA cookies are provided. (This saves the cost of a bp_mapin() on buffers being transferred from the filesystem.) SDA_PROP_CAP_HIGHSPEED - future expansion for high-speed clocking SDA_PROP_CAP_8BITS - future expansion for 8-bit MMC bus SDA_PROP_CAP_LOWV - future expansion for low voltage (1.8V) cards SDA_PROP_CAP_INTR - future expansion for SDIO interrupt support int (*so_poll)(void *private); This function is used to poll the device when interrupts have been disabled, such as when a panic() is in progress. The device must not sleep, and should attempt to poll for completion on any outstanding commands. 5.2 Functions ------------- The following funcctions are exported by SDA for the nexus driver to use: void sda_host_init_ops(struct dev_ops *); void sda_host_fini_ops(struct dev_ops *); The host driver calls these in its _init() and _fini() entry points to populate the bus_ops entry point in the dev_ops. (There may also be changes to update cb_ops in the future, though not for Phase I.) sda_host_t *sda_host_alloc(dev_info_t *dip, int nslot, sda_ops_t *ops, ddi_dma_attr_t *attrp); This allocates a host structure, and the host driver calls it once for each driver instance. nslot is the number of slots available on the instance. ops is a structure of operations that the nexus driver supports. See the sda_ops_t description in 5.1 above. The attrp is the DMA attributes of the host driver. void sda_host_free(sda_host_t *); This frees previously allocated host state. void sda_host_set_private(sda_host_t *host, int slotnum, void *private); This associates the opaque private pointer with given host and slot. The private pointer must be set prior to calling sda_host_attach, and will be used as the first argument to the various entry points in the sda_ops structure. int sda_host_attach(sda_host_t *); This "attaches" the SD host (and all of its slots) to the framework. This should be called after interrupts are enabled, as the first thing the framework will do is attempt to detect and initialize any inserted card. void sda_host_offline(sda_host_t *); This detaches the host from the system, and releases any associated resources in the framework. void sda_cmd_done(sda_cmd_t *cmd, int errno); The nexus driver calls this when the command phase for cmd has finished. The errno indicates the completion status of the command. Note that commands which involve a data transfer phase or use the busy bit (response types R1b and R5b) may have this called while the DAT lines are still active. (I.e. the nexus driver shall not wait for the DAT lines to become idle before calling this.) If errno is non-zero, then the cmd will not have a data phase associated with it. void sda_transfer_done(sda_cmd_t *cmd, int errno); The nexus driver calls this when a command that was making use of DAT lines (such as a command with response type R1b or R5b, or a command with a data transfer associated) has finished completely. The errno is non-zero if there was any problem with the transfer (e.g. ETIMEDOUT if the operation took too long, etc.) void sda_host_detect(sda_host_t *host, int slot_num); This is called by the device driver when a card has been inserted to or removed from the named slot_num. The framework will subsequently call the driver's so_getprop() routine with SDA_PROP_INSERTED to determine whether a card is physically present in the system or not. (The driver should call this in response to a change in the SDCD# signal level, for example.) void sda_host_err(sda_host_t *host, const char *format, ...); void sda_host_log(sda_host_t *host, const char *format, ...); These are printf-like messaging functions. host may be NULL. sda_host_err indicates an error, and will cauase cmn_err(CE_WARN, ...) to be used. sda_host_log is an informational message that is only sent to the system log, and will not not be displayed on the console. APPENDIX A: Interface Tables ============================== Here are the interface tables: Imported Interfaces Imported Interface Stability Comments ---------------------------------------------------------- blk2scsa Consolidation Private PSARC 2007/654 Exported Interface Stability Comments ---------------------------------------------------------- drv/sdhost Volatile sdhost device driver name drv/sdcard Volatile sdcard device driver name misc/sda Consolidation Private sda common API support sys/sdcard/sda.h Consolidation Private sda common API header sda_mem_init() Project Private memory card API sda_mem_fini() Project Private memory card API sda_host_init() Consolidation Private nexus API sda_host_fini() Consolidation Private nexus API sda_host_alloc() Consolidation Private nexus API sda_host_free() Consolidation Private nexus API sda_host_attach() Consolidation Private nexus API sda_host_detach() Consolidation Private nexus API sda_host_set_private() Consolidation Private nexus API sda_host_detect() Consolidation Private nexus API sda_cmd_done() Consolidation Private nexus API sda_transfer_done() Consolidation Private nexus API sda_host_err() Consolidation Private nexus API sda_host_log() Consolidation Private nexus API struct sda_host Consolidation Private nexus API opaque host handle struct sda_ops Consolidation Private nexus API operations vector struct sda_cmd Consolidation Private nexus API operations SDA_OPS_VERSION Consolidation Private nexus API operations version SDA_CMDF_* Consolidation Private nexus API command flags SDA_PROP_* Consolidation Private nexus API slot properties APPENDIX B: References ======================= [1] SD Specifications Part 1: Physical Layer Simplified Specification, Version 2.00, September 25, 2006 (www.sdcard.org) [2] SD Specifications Part A2: SD Host Controller Simplified Specification, Version 2.00, February 8, 2007 (www.sdcard.org) [3] SD Specifications Part E1: SDIO Simplified Specification, Version 2.00, February 8, 2007 (www.sdcard.org) [4] Generic Block Device to SCSA Translation Layer, Functional Specification, Garrett D'Amore, November 13, 2007, PSARC 2007/654