Pawel Wojcik's Weblog Pawel Wojcik's Weblog

Thursday Feb 01, 2007

In previous parts of the overview I have described the general Solaris SATA architecture and the interface betwen sata module and HBA drivers. Let's see how the sata module and HBA drivers initialize themselves and register with the scsi layer.

SATA HBA drivers are linked with the '-n' option specifying that the sata module have to be loaded before the sata HBA driver. So when the sata HBA driver is identified as a proper driver for a given SATA controller type, the sata module is loaded and initialized before the driver _init and attach routine is called. From _init function sata HBA driver calls sata_hba_init() routine, passing a pointer to its modldrv structure. Sata module follows up with calling scsi_hba_init(), passing up the pointer to the HBA modldrv structure, but replacing the driver's devo_cb_ops with it's own devo_cb_ops structure, allowing it to capture open, close and ioctl calls directed to the driver instance. Scsi_hba_init routine registers the sata hba driver/sata module instance combination as an instance of scsi HBA driver. Note, that this calling sequence is executed only once for a sata hba driver, regardless of a number of HBA instances that will be controlled by the HBA driver. The Solaris kernel will call HBA driver attach routine once for each instance of the sata controller.

SATA HBA driver actions:

Each sata HBA driver has to do following in its attach function (simplified list):

  • allocate and initialize data structures specific for this controller instance;
  • allocate/initialize all mutexes needed for multithreaded operation;
  • map any controller registers;
  • allocate DMA resources necessary for controller operation;
  • detect suported interrupt type and register interrupts with the system;
  • perform sata controller's initialization, including PHY setup (if necessary).

At this point the controller and the HBA driver has to be ready to perform any operation asked for by the sata module, including sending commands to an atached SATA device. The final step, from the sata HBA driver point of view, is to call sata_hba_attach() function, passing to the sata module the sata_hba_tran structure (described in previous part of the overview). The HBA-specific part of the initialization is completed and the rest of the initilization is now driven by the sata module from within the sata_hba_attach(0 function.

SATA module actions:

For each sata HBA instance, SATA module creates sata_hba_inst structure, to which all others instance-specific pieces of data are attached. All sata_hba_inst structures are double-linked into a list, allowing dynamic insertion and removal of new sata HBA instances.

Do you remember that sata hba instance/sata module pretends to be a scsi hba instance? For each controller instance being attached, sata module has to create a scsi_hba_tran structure for the scsi layer. Scsi_hba_tran is an equivalent of sata_hba_tran structure described before, that sata module uses to interface with a specific instance of the sata HBA. Scsi_hba_tran structure contains entry points of the scsi hba driver through which a generic scsi layer interfaces with the specific instance of the scsi hba driver. All these entry points (functions) are contained in sata module. The newly created scsi_hab_tran structure is sent to scsi layer as a parameter of scsi_hba_attach_setup() call.

After scsi_hba_tran is created and successfully registered with scsi layer, sata module links both sata and scsi structures to the newly created sata_hba_inst structure, and stores there a pointer to the HBA's devinfo. SATA HBA devinfo structure is used to identify HBA instance by all parties involved in the operation: sata hba driver, sata module and scsi layer.

Few other sata module internal initialization is performed, among others a creation of a control node used by the system for open, close and ioctl operation for this HBA instance.

Note, that up to this point sata module did not talk to sata HBA driver. Now, the interfaces between the sata module, sata hba driver instance and the rest of the systems are set-up. Sata module is ready for the most interesting part of the initialization - detecting attached SATA devices, identifying them and making them accessible for the system.

SATA ports probing and device attachment:

SATA modules knows how many SATA device ports are active on the attaching SATA controller - this information was made available via sata_tran argument (pointer to the sata_hba_tran structure) of the sata_hba_attach(). It is worthwhile to notice, that SATA controller may have more device ports than those physically available for attaching SATA devices - sata HBA driver has to report only the number of device ports where SATA device may be connected (this situation may occur when a motherboard manufacturer reduces number of available SATA ports even though an embedded controller is capable of supporting a greater number of ports). These ports are addressed in the range of '0' to 'number_of_ports minus one', so sata HBA drive may have to maitain the mapping of these port numbers to the actual physical ports. SATA module creates an internal representation of each SATA port and a connected device. I have mentioned before that the anchor point of internal sata module structures related to a HBA instance is sata_hba_inst structure. Other structures are linked to it in the 'tree' fashion, as shown in the example below:

                        sata_hba_inst (SATA controller)
                              |
      ---------------------------------------------------- .....
      | (device port)         | (device port)            | (device port)
      |                       |                          |
sata_cport_info        sata_cport_info             sata_cport_info
      |                       |                          |
sata_drive_info        sata_pmult_info              (no device)
   (device)           (port multiplier)
                              |
                  --------------------------- ....
                  |                         |
          sata_pmport_info           sata_pmport_info
	 (port multiplier's          (port multiplier's
           device  port)                device port)
                  |                         |
              (no device)             sata_drive_info
                                         (device)

Since the number of SATA device ports remains static, sata module creates an attachment point for each of the SATA port, regardless if there is a device connected to it or not. An attachment point is a 'location' where a SATA device may be connected. Within the Solaris system, it is represented by a minor node, created by the sata module. The system may monitor the state of the attachment point by issuing DEVCTL IOCTLs request for such minor node. The name of the node (as visible in /devices/'controller path'/) is based on the SATA device port number. The macro SATA_MAKE_AP_MINOR in sata.h file describes how the minor node name is composed.

Now sata module checks what is the state of the SATA device port, i.e. is the port active, what is the status of the serial link and is any device connected to the port. The sata HBA driver's entry point sata_tran_probe_port is used to request port probing.

In response, sata HBA driver has to return the state of the port ( SATA_PSTATE_PWRON, SATA_PSTATE_PWROFF, SATA_PSTATE_SHUTDOWN or SATA_PSTATE_FAILED), a content of the standard SATA port registers and a type of the attached device (SATA_DTYPE_XXXX , specified in sata_hba.h file). At this point sata module is interested only in finding whether there is any device attached and whether the attached device is a port multiplier. If there is no device connected to the port - there is nothing to do. If there is a port multiplier connected to the port, a special probing sequence is required (even though port multipliers are not supported yet). When there is any other device connected, the device itself is probed.

Serial ATA specification dictates that SATA device after the reset should provide so-called 'device signature'. It is a hex value read from one of the task file registers that identifies the type of the device. The device signature is made available to the driver by majority of SATA controllers, but unfortunately not all. To accomodate all controllers, sata module does not rely on the device type identified by the sata HBA driver through the device signature value (and passed via device_type field of the sata_device structure), but instead probes a connected device itself by issuing Device Identify command to this device (using sata_tran_start entry point). The first word of the returned Identify Device data describes the device type. ATAPI devices do not respond to this command, so if Identify Device command fails, sata module tries to send Identify Packet Device command to check if the attached device is of the ATAPI type rather than ATA type. The entire Identify Device (or Identify Packet Device) data is stored in a sata_drive_info structure. Various device-related information are later extracted from this data.

Only SATA disk devices are supported at this time. If such device is identified, sata module tries to initilialize it to a know state. What is the known state? - The initial setting of the DMA mode and read and write cache mode. Even if setting of the initial mode fails for some reason, the device is still usable, but possibly with a degraded performance. For each device fund, there is a series of messages logged in the system log, describing what was found and what are some of the device capabilities.

Last step in the port probing during the HBA attach is making a connected device accessible to the system. System accesses all devices through their corresponding device nodes, so sata module creates target device nodes for each connected and accessible disk device. The target device node name is based on a compatible property. In SATA disk case, the name of the node is "disk", unlike the parellel scsi disk target node which (for historical reasons) is based on the name of the target driver name, 'sd". The target node, to be addressed the same way as the scsi device, has to have following properties set:

  • 'device-type' ("scsi"),
  • 'target' (scsi target number, based in this case on controller's device port number and potentially port multiplier's device port number),
  • 'lun' (always set to zero for SATA disks),
  • 'compatible' (list of all compatible strings).
Now the generic ndi_devi_online() function is called to attach just created target node to the device tree, identify the appropriate target driver (sd in this case) and put the device online. The onlining of the scsi device involves sending a series of command to the drive, because the target driver needs to get information about the new device and configure it according to its own rules. If this procedure succeeds, the device may be accessed by the system.

After all SATA device ports are processed as described above, the HBA attach sequence is completed. Sata module can now process requests from the scsi target driver directed to each onlined sata device. The described sequence is a bit simplified - for details one has to check the code istelf. But I hope that it helps to understand to read the sata module code.

TO BE CONTINUED.

Wednesday Jan 17, 2007

SATA framework has to interface with Solaris scsi layer and sd target driver on one end (see the chart in the first part of the overview) and with SATA HBA driver on the other end. Let's first consider interface with SATA HBA driver. The interface between sata module and sata hba drivers is defined in usr/src/uts/common/sys/sata/sata_hba.h header file. SATA framework concerns itself with the generic operations, common for all SATA HBA. But it have to consider HBA capabilities, when it generate I/O and control requests. Also, it has to export some of these capabilities to the system, particularly DMA capabilities. SATA HBA driver exports its capabilities and entry points via sata_hba_tran structure, analogous to scsi_hba_tran structure. This structure contains:

  • Pointer to the SATA controller hardware instance node
  • Controller DMA attributes used for I/O data transfer (see man page for ddi_dma_attr)
  • Features supported by the controller, such as command queuing, native command queuing, ATAPI, Port Multipliers, etc. One-bit flags are used to indicate that specific feature is supported.
  • Number of sata device ports present/usable on the controller (SATA devices may be connected to those ports).
  • Queue depth supported by the controller
  • Pointers to the HBA driver functions used to:
    • Probe ports, to find the state of the port and presence/absence of a device.
    • Transport sata packet to the HBA driver, specifying some SATA device operation.
    • Abort sata packet (or packets) execution.
    • Reset sata device, device port or entire controller.
    • Initiate self-test.
    • Activate/deactivate sata device port.
Here is the complete structure definition (refer to usr/src/uts/common/sys/sata/sata_hba.h header file for details):
struct sata_hba_tran {
        int             sata_tran_hba_rev;      /* version */
        dev_info_t      *sata_tran_hba_dip;     /* Controler dev info */
        ddi_dma_attr_t  *sata_tran_hba_dma_attr; /* DMA attributes */
        int             sata_tran_hba_num_cports; /* Num of HBA device ports */
        uint16_t        sata_tran_hba_features_support; /* HBA features */
        uint16_t        sata_tran_hba_qdepth;   /* HBA-supported queue depth */

        int             (*sata_tran_probe_port)(dev_info_t *, sata_device_t *);
        int             (*sata_tran_start)(dev_info_t *, sata_pkt_t *);
        int             (*sata_tran_abort)(dev_info_t *, sata_pkt_t *, int);
        int             (*sata_tran_reset_dport)(dev_info_t *,
                                        sata_device_t *);
        int             (*sata_tran_selftest)(dev_info_t *, sata_device_t *);

                                                /* Hotplug vector */
        struct sata_tran_hotplug_ops *sata_tran_hotplug_ops;

                                                /* Power mgt vector */
        struct sata_tran_pwrmgt_ops *sata_tran_pwrmgt_ops;

        int             (*sata_tran_ioctl)(dev_info_t *, int, intptr_t);
};

When SATA framework calls one of the interface function supplied by the SATA HBA driver, it passes as one of the arguments the pointer to the device info that is specific for a given instance of the controller hardware. SATA HBA driver is using it to identify on which controller the operation is to be executed. It is important to note that by refering to the controller instance we refer to an individual hardware node in a device tree, created when the system is configured during the boot process. Such node does not necessarily corresponds to a physical controller chip, which may contain a number of independent controllers.
Specifying a controller instance is obvioulsy not enough - an additional information is needed to identify to which device or a device port apply an operation. This info is passed either directly as a pointer to sata_device addressing structure, or indirectly though the sata packet (sata_pkt) structure which embedds sata_device structure. Specifying sata port is simple - sata ports are numbered from 0 to max number of available data ports on the controller. But we also need to consider that a port multiplier may be connected to the controller's port, so in addition to the controller's port, the device port beyond the port multiplier has to be specified. To indicate when this secondary information is valid, the type of addressing (adress qualifier) is also included in the sata_address structure embedded in sata_device.

struct sata_address {
        uint8_t         cport;          /* Controller's SATA port number */
        uint8_t         pmport;         /* Port Multiplier SATA port number */
        uint8_t         qual;           /* Address Qualifier flags */
        uint8_t         pad;            /* Reserved */
};

The sata_device structure (see sata_hba.h file for definition) is used not only to address specific sata device or sata port, but also to inform the SATA framework about the state of the port (including content of standard port registers) or device and about an attached device type. The state of the port has to be always returned to SATA module by SATA HBA driver, regardless of the type of the operation initiated by SATA module.

The forth imnportant (may be the most important) interface structure is sata packet structure (sata_pkt). Sata packet carries description of the operation that SATA framework is requesting from SATA HBA driver. When the operation is completed, the satus of the operation is returned to SATA module in the same structure.

struct sata_pkt {
        int             satapkt_rev;            /* version */
        struct sata_device satapkt_device;      /* Device address/type */

                                                /* HBA driver private data */
        void            *satapkt_hba_driver_private;

                                                /* SATA framework priv data */
        void            *satapkt_framework_private;

                                                /* Rqsted mode of operation */
        uint32_t        satapkt_op_mode;

        struct sata_cmd satapkt_cmd;            /* composite sata command */
        int             satapkt_time;           /* time allotted to command */
        void            (*satapkt_comp)(struct sata_pkt *); /* callback */
        int             satapkt_reason;         /* completion reason */
};
The sata packet contains embedded sata_device addressing structure, mode of operation, SATA command to be passed to a sata device, a time allowed for the execution, and a status of the execution.
Two pointers are embedded in sata packet - one (satapkt_framework_private) is used to link the packet with SATA module internal structures and original scsi packet (if any). This pointer should not be ever modified by the SATA HBA driver.
The other embedded pointer could be used by the SATA HBA driver to link the packet with its own internal data structures related to the addressed device and the packet execution.
The pointer to a callback function allows queuing the sata packet in SATA HBA driver for delayed execution and an immediate return to the SATA module. When the operation specified by the sata packet completes, the callback function is called, with the sata packet passed as the argument.
The status of the operation is returned two ways. The completion reason specifies general reason for the completion, i.e. success, rejection due to a full packet queue, unsupported operation or unspecified driver busy condition, or a failure due to some serial link problems or error returned by the device (see sata_hba.h for details). Some additional information about a failure reason are returned either in embedded sata_device structure (port or serial link problem) or in sata command structure (satapkt_cmd) when an error was reported by the actual sata device.

The last, but not the least important structure is sata_cmd structure, embedded in the sata packet. Sata_cmd is set-up by the SATA module and specifies the content of the task file registers. Task file registers compose a set of registers used to transfer information to a sata device. In old parallel ATA word these registers were directly accessible by the IDE controller. In SATA, their content is transfered to/from the sata device via packets send through a serial link. SATA specification retained the concept of the task file registers for a software compatibility reason. It uses the ATA/ATAPI command formats, and those commands are based on task file registers interface
So, when SATA module wants to execute specific SATA command, it sets up the content of every relevant register (for a given command) in the task file register. The SATA HBA driver does not have to interpret anything, just takes prepared register content and passes it, in a controller-specific fashion, to a sata device (sometimes stuffing it into "shadow" task file registers, sometimes building complete Frame Information Structure - a packet being transfered via serial link).

struct sata_cmd {
        int             satacmd_rev;            /* version */
        struct buf      *satacmd_bp;            /* ptr to buffer structure */
        struct sata_cmd_flags  satacmd_flags;
        uint8_t         satacmd_addr_type;      /* addr type: LBA28, LBA48 */
        uint8_t         satacmd_features_reg_ext; /* features reg extended */
        uint8_t         satacmd_sec_count_msb;  /* sector count MSB (LBA48) */
        uint8_t         satacmd_lba_low_msb;    /* LBA Low MSB (LBA48) */
        uint8_t         satacmd_lba_mid_msb;    /* LBA Mid MSB (LBA48) */
        uint8_t         satacmd_lba_high_msb;   /* LBA High MSB (LBA48) */
        uint8_t         satacmd_sec_count_lsb;  /* sector count LSB */
        uint8_t         satacmd_lba_low_lsb;    /* LBA Low LSB */
        uint8_t         satacmd_lba_mid_lsb;    /* LBA Mid LSB */
        uint8_t         satacmd_lba_high_lsb;   /* LBA High LSB */
        uint8_t         satacmd_device_reg;     /* ATA dev reg & LBA28 MSB */
        uint8_t         satacmd_cmd_reg;        /* ata command code */
        uint8_t         satacmd_features_reg;   /* ATA features register */
        uint8_t         satacmd_status_reg;     /* ATA status register */
        uint8_t         satacmd_error_reg;      /* ATA error register  */
        uint8_t         satacmd_acdb_len;       /* ATAPI cdb length */
              ..........
        int             satacmd_num_dma_cookies; /* number of dma cookies */
                                                /* ptr to dma cookie list */
        ddi_dma_cookie_t *satacmd_dma_cookie_list;
};
Other interesting part of the sata_cmd structure is dma cookie list. This list contains adresses and lengths of the regions in the system physical memory, and it is used to set-up DMA controller's scatter-gather list. SATA module makes sure that each specified "chunk" of memory would match the capability of the HBA's DMA controller with respect to an address range and a transfer size (Remember DMA attributes that SATA HBA passed in sata_hab_tran structure? They are used for this transfer "limiting" purpose). Once a sata device executes the command, it returns the status of the operation in the status "register" of task file registes set . If the operation was successfull, SATA HBA driver just have to return a general 'completion reason'. If the operation failed, SATA device returns error information (command specific) in various registers. SATA HBA driver has to collect this information from the device (from "shadow" registers or from register FIS) and store it back in the sata_cmd structure. When the sata_pkt is returned to SATA module, the 'completion reason' in conjunction with additional information in sata_cmd let SATA module to determine the cause of the failure and the information that may need to be passed to other system software.

TO BE CONTINUED

Friday Jan 12, 2007

In previous part I have shown where SATA Framework and SATA HBA drivers are placed in Solaris and what are SATA Framework features/functionality. Let's see what SATA HBA driver has to offer:

SATA HBA driver role is to take care of the SATA controller hardware and its operation. SATA HBA driver is not aware of SCSA interface requirements nor SCSI-to-SATA translations.

The SATA HBA driver compatible with SATA framework compatible has to take care of:
  • Any hardware specific mapping of the SATA controller registers and resources.
  • Controller-related DMA setup and control (controller's registers and controller-specific data structures accessed via DMA).
  • PHY link control and device detection.
  • Interrupt registration and handling.
  • Detection of hotplugging events.
  • Hardware specific setup and transfer of ATA/ATAPI commands, data and error information via serial link.
  • Perform power management operations requested by the system.
Interacting with SATA HBA framework, SATA HBA driver has to:
  • Register itself with the SATA HBA framework.
  • Expose its capability and configuration.
  • Report state and changes of state of the SATA device ports.
  • Execute operation requests specified by SATA framework in sata packets.
  • Return status of the operations to the SATA framework.
  • All access to the SATA HBA driver (and SATA HBA) is via SATA framework. SATA HBA framework presents to the system each registered instance of the SATA HBA as the SCSI HBA instance. It means, that the rest of the system really see only the scsi HBA and is not aware of the type if the interconnect (serial ATA in this case). The basic functionality of a scsi HBA driver is provided by the combined SATA framework and SATA HBA driver functionality. Attached SATA devices are treated by the system as SCSI devices and are controlled by the sd target driver via scsi transport layer.

    Devices

    SATA devices, similarly to scsi devices, are represented in the device tree by the target nodes. Unlike scsi devices, which are connected to a shared scsi bus, SATA devices are connected point-to-point to SATA controller device ports. The classical mechanism of scsi device discovery and configuration is therefore not needed, because there is no need to scan any bus. SATA controller knows that a device is connected to given SATA device port and the link with a device is established automatically. With this understanding we can consider SATA target devices as self-identifying devices, that do not depend on driver.conf entries to be recognized by the system (see Solaris man page for 'scsi').
    So the target nodes (corresponding to attached and configured devices) and their properties are created dynamically (using standard nexus mechanisms) by SATA framework. This operation is performed during SATA HBA instance attachment process and when a connected device is configured for use by the system via cfgadm operation (more about it later). Target nodes are also destroyed by SATA framework when a device is disconnected/removed from a SATA device port. From the application point of view, SATA device is referred to like a scsi device, using the same naming convention and device path, e.g. /dev/dsk/cXtYd0.

    I/O Operations

    Operations for scsi device are specified by the target driver using scsi packet (see man page for 'scsi_pkt'). Since SATA framwork/SATA HBA pair registers itself as scsi HBA, it receives operational directives from the target driver in scsi packets and, optionally, as IOCTL request.
    Operations specified by scsi packets are translated by SATA HBA framework into equivalent SATA device operations (in SATA packet envelope) or are emulated within the SATA framework, or are rejected if none of the above could be done. The translation may be quite involved (even multi-phased), particularly for scsi commands that do not have direct equivalent is SATA command set.

    Any data transfer to/from the SATA device involves data buffer. Some data may be transfered via PIO transfer, but majority of the data transfer is performed using DMA. SATA framework assumes that all data is transfered via DMA. To relieve SATA HBA driver from data transfer DMA setup operations, SATA framework performs data buffer DMA mapping and DMA resources allocation, based on the information in the scsi packet. Even when the operation involving data transfer originates in the SATA framework (no scsi packet involved), the DMA setup is performed by the framework. What is involved here: DMA handle allocation and binding, partial DMA mapping management, DMA windows and cookies management, and occasionally an intermediate buffer allocation. While allocating DMA resources, SATA HBA framework takes into consideration SATA HBA capabilities and attached device capabilities - this needs to be done, because SATA devices use different command set and have different I/O capabilities than scsi devices and scsi-type requests needs to be adjusted such a way that they could be performed by SATA device.

    SATA framework sends to a SATA HBA driver (via SATA HBA Interface) a sata packet, one packet per single SATA device operation. Sata packet contains (among other data) a fully formed SATA device command, including standard registers (ATA task file registers) setup. SATA HBA driver uses this data in the sata packet without any further translation to set-up, in the controller-specific way, an I/O operation.
    The status of the SATA operation, including potential error information, is translated into SCSI format (as needed for scsi packet) by SATA HBA framework and send back to the scsi target driver.

    Control

    SATA HBA framework creates also control node for each SATA controller. This is an equivalent of the control node for scsi controller. All IOCTLs for a given controller are addressed to its control node. Device control IOCTLs are processed by the SATA HBA framework and are translated into SATA operations, if necessary. IOCTLs that are not handled by SATA HBA framework are passed either to standard nexus IOCTL handler (ndi_devctl_ioctl()) or to the SATA HBA driver, if possible (i.e. if HBA driver registered entry point for IOCTL requests).

    Hotplugging

    As I mentioned before, SATA controllers detects device physical (electrical) connection and disconnection. Device electrical connect/disconnect - hotplugging events - detected by the SATA HBA driver are passed to the SATA framework, which in response performs device detection, internal configuration/reconfiguration and error handling operations and informs the system about hotplugging events via sysevents. Hot-plugged devices are not immediately usable by the system - an explicit operator intervention is needed to configure such device and make it accessible by the system (more about this later).


    The brief descriptions above will be expanded in following sections, where we will talk about interfaces, driver attach operations, device configuration, scsi operation setup/translation, sample read/write operations, events handling, internal structures, cfgadm operations and details of various operations.

Thursday Jan 11, 2007

As many of you noticed, Solaris now supports SATA controllers and devices. To simplify writing SATA HBA drivers the new module and a set of interfaces was created, referred to as either SATA Framework or SATA module. I was a principal architect of SATA framework, but several other Sun engineers were participating in the conceptual design and the shaping of the interfaces.
It is not small piece of software - the source, sata.c, is over 300k in size. Reading this code, with associated header files may be a little confusing. So, I created an overview of the sata module, explaining what it is, how it fits in Solaris kernel, what it does, what are the interfaces and how sample operations are performed. Hopefully, it will be useful for all that want to improve and expand SATA support in Solaris Similar overview was presented about a year ago at Silicon Valley Open Solaris User Group meeting in Santa Clara and on various occasions internally in Sun organization. The overview that I plan to present here will have several parts. Here is the first one...

Up to the time of introduction of SATA Framework, Solaris support for SATA controllers was limited to controllers operating in a compatibility mode, emulating generic, parallel ATA controllers. Only generic ATA interfaces are used, i.e. task files registers and bus master control registers. This was clearly inadequate for SATA controllers not implementing standard ATA interfaces and for providing fine-control access to serial interfaces and SATA-native features. Hotplugging feature in particular was not supported in existing pci-ide/ata framework. Queuing, particularly SATA NCQ could not be supported without extensive changes to pci-ide and ata driver.

The goals of the SATA framework project:
  • Facilitate usage of existing Solaris scsi layer and common scsi target driver.
  • Provide common processing and algorithms that all SATA HBA drivers using scsa and scsi target driver would otherwise have to implement.
  • Provide native SATA support (as opposed to emulating legacy IDE devices),
  • Provide configuration management and hotplugging support for SATA HBA drivers.
  • Minimize SATA HBA driver complexity.
  • Provide platform neutrality.
  • Provide stable interface suitable for a third-party driver developers.
Why SCSI? Because Solaris scsi layer and target driver (sd) are a mature drivers (however imperfect) with already tried and tested capabilities and features. Furthermore, device naming and handling would appear to other system entities/application layers the same as for scsi devices. And lastly, T10 standard body and SATA manufacturers fairly early started an effort to define common definitions and and requirements for emulating SCSI device behavior.
SATA HBA Framework was intended as the support module interfacing SATA HBA driver (hardware specific) with existing Solaris SCSI framework. The goal was to isolate hardware-specific SATA HBA driver from SCSI related operations and interfaces and to implement generic, SATA-specific operations for use by SATA HBA driver. SATA HBA driver could be then concerned only with hardware initialization and interface to attached SATA devices, while SATA HBA Framework would implement generic SATA operations and interface with generic SCSA framework and SCSI target drivers.
SATA HBA driver in conjunction with SATA HBA Framework would be treated by SCSI framework as an SCSI HBA driver. SATA HBA Framework and SATA drivers are intended to be platform-neutral - common code would be used on x86, x64 and sparc based platforms (existing ATA support in Solaris uses different drivers on x86/x64 and sparc platforms). Additional goal was to make SATA HBA Framework interface public, thus allowing third-party developers to write simple SATA HBA drivers without Sun engineers involvement.

Basic Architecture Model:
                    +-----------------+
                    |     cfgadm      | existing
                    +-------^---------+
                            |
                            v
                    +=================+
               new  | SATA Hot Plug   | SATA specific
                    | library         | plug-in
                    +=======^=========+ library
                            |                            Solaris I/O
                            |                                ^
                            |              USER              |
      ======================|================================|================
                            |             KERNEL             |
                            |                        +-------v---------+
             cfgadm plug-in |                        |   SD driver     | existing
                     IOCTLs |                        | (target driver) |
                            |                        +-------^---------+
                            |                                ^
                            |             SCSA               |
                  +=========v==========+  Interface  +-------v---------+
             new  | SATA HBA Framework |<----------->| SCSI Framework  | existing
                  +=========^==========+             +-----------------+
                            |
                            | SATA HBA
                            | Interface
                            |
                  +=========v==========+
              new | SATA HBA Driver    |
                  | (eg. AHCI driver)  |
                  +====================+
                            |
                            V
           ( SATA devices: SATA disks, SATA ATAPI CDROMs, ...)


SATA Framework features:
  • Implemented as a loadable kernel module.
  • Implements and exports generic SCSI HBA interface.
  • Performs initial SATA devices configuration and setup.
  • Emulates SCSI operations that have no equivalent in SATA.
  • Translates SCSI operations into appropriate SATA operations.
  • Controls SATA operation sequences needed for SCSI operations.
  • Provides data buffer DMA resources setup.
  • Translates SATA operation status and error information into SCSI.
  • format.
  • Provides devctl interface for cfgadm.
  • Controls hotplugging and operator-directed operations.
  • Performs dynamic reconfiguration based on asynchronous hotplugging events.
  • Generates sysevents that may be consumed/monitored by other system entities.


TO BE CONTINUED....