harmony 鸿蒙SCSI Peripheral DDK Development

  • 2025-06-06
  • 浏览 (24)

SCSI Peripheral DDK Development

Overview

Small Computer System Interface (SCSI) devices, such as disk arrays, tape libraries, and specific types of storage servers, are widely used in enterprise-level storage solutions and industrial application scenarios. If the operating system does not have an adaptation driver for these devices, the devices cannot be identified or used after being connected. SCSI Peripheral Driver Development Kit (DDK) is a suite provided for SCSI device driver development. It allows you to develop SCSI device drivers at the application layer based on the user mode.

The SCSI Peripheral DDK supports seven common commands (including INQUIRY, READ CAPACITY, TEST UNIT READY, REQUEST SENSE, READ, WRITE, and VERIFY) in the three command sets: SCSI Primary Commands (SPC), SCSI Block Commands (SBC), and Multimedia Commands (MMC). You can use these commands at your preference.

Basic Concepts

Before developing the SCSI Peripheral DDK, you must understand the following basic concepts:

  • SCSI

    SCSI is a standard protocol set used for communication between computers and peripherals such as hard disk drives, tape drives, optical disk drives, and scanners.

  • AMS

    The Ability Manager Service (AMS) is a system service used to coordinate the running relationships of abilities and schedule the lifecycle of abilities.

  • BMS

    The Bundle Manager Service (BMS) is responsible for application installation, uninstallation, and data management on OpenHarmony.

  • DDK

    The Driver Development Kit (DDK) is a tool package provided by OpenHarmony for developing drivers for non-standard SCSI peripherals based on the peripheral framework.

  • Non-standard peripherals

    Non-standard peripherals (also called custom peripherals or dedicated peripherals) are peripherals that do not comply with general standards or are customized for specific application scenarios. This type of device usually requires special software support or special interfaces to implement communication with the host system.

  • Standard peripherals

    Standard peripherals refer to peripherals (such as USB keyboards and mouse devices) that comply with industry standards and specifications. Such devices typically have uniform interface protocols, physical dimensions, and electrical characteristics, so that they can be used interchangeably between different systems.

  • Logical block

    A logical block is a basic data storage unit. It represents a data area of a fixed size on a device and is usually used for data read and write operations. The size of a logical block may be 512 bytes, 1024 bytes, 2048 bytes, and so on. A specific size depends on a configuration of the device and a design of the file system.

  • CDB

    A command descriptor block (CDB) is a standard data structure used to send commands in the SCSI protocol. A CDB is a byte array with a fixed length. It contains the operation code (Opcode) and related parameters of the SCSI command and is used to instruct the device to perform operations (such as read, write, and query).

Implementation Principles

A non-standard peripheral application obtains the SCSI device ID by using the peripheral management service, and delivers the ID and the action to the SCSI driver application through RPC. The SCSI driver application can obtain the basic information about the SCSI device and read and write data by invoking the SCSI Peripheral DDK API. Then, the DDK API uses the HDI service to deliver instructions to the kernel driver, and the kernel driver uses instructions to communicate with the device.

Figure 1 Principle of invoking the SCSI Peripheral DDK

SCSI_Peripheral_DDK schematic diagram

Constraints

  • The open APIs of SCSI Peripheral DDK support the development of standard SCSI peripheral drivers.

  • The open APIs of SCSI Peripheral DDK can be used only within the lifecycle of DriverExtensionAbility.

  • To use the open APIs of SCSI Peripheral DDK, you need to declare the corresponding ACL permission ohos.permission.ACCESS_DDK_SCSI_PERIPHERAL in module.json5.

Environment Setup

Before you get started, make necessary preparations by following instructions in Environment Preparation.

How to Develop

Available APIs

Name Description
int32_t OH_ScsiPeripheral_Init(void) Initializes the SCSI Peripheral DDK.
int32_t OH_ScsiPeripheral_Release(void) Releases the SCSI Peripheral DDK.
int32_t OH_ScsiPeripheral_Open(uint64_t deviceId, uint8_t interfaceIndex, ScsiPeripheral_Device **dev) Opens the SCSI device specified by deviceId and interfaceIndex.
int32_t OH_ScsiPeripheral_Close(ScsiPeripheral_Device **dev) Disables the SCSI device.
int32_t OH_ScsiPeripheral_TestUnitReady(ScsiPeripheral_Device *dev, ScsiPeripheral_TestUnitReadyRequest *request, ScsiPeripheral_Response *response) Checks whether the logical units are ready.
int32_t OH_ScsiPeripheral_Inquiry(ScsiPeripheral_Device *dev, ScsiPeripheral_InquiryRequest *request, ScsiPeripheral_InquiryInfo *inquiryInfo, ScsiPeripheral_Response *response) Queries basic information about the SCSI device.
int32_t OH_ScsiPeripheral_ReadCapacity10(ScsiPeripheral_Device *dev, ScsiPeripheral_ReadCapacityRequest *request, ScsiPeripheral_CapacityInfo *capacityInfo, ScsiPeripheral_Response *response) Obtains the capacity information about the SCSI device.
int32_t OH_ScsiPeripheral_RequestSense(ScsiPeripheral_Device *dev, ScsiPeripheral_RequestSenseRequest *request, ScsiPeripheral_Response *response) Obtains sense data, that is, information returned by the SCSI device to the host, which is used to report the device status, error information, and diagnosis information.
int32_t OH_ScsiPeripheral_Read10(ScsiPeripheral_Device *dev, ScsiPeripheral_IORequest *request, ScsiPeripheral_Response *response) Reads data from a specified logical block.
int32_t OH_ScsiPeripheral_Write10(ScsiPeripheral_Device *dev, ScsiPeripheral_IORequest *request, ScsiPeripheral_Response *response) Writes data to a specified logical block of a device.
int32_t OH_ScsiPeripheral_Verify10(ScsiPeripheral_Device *dev, ScsiPeripheral_VerifyRequest *request, ScsiPeripheral_Response *response) Verifies a specified logical block.
int32_t OH_ScsiPeripheral_SendRequestByCdb(ScsiPeripheral_Device *dev, ScsiPeripheral_Request *request, ScsiPeripheral_Response *response) Sends the SCSI command in CDB mode.
int32_t OH_ScsiPeripheral_CreateDeviceMemMap(ScsiPeripheral_Device *dev, size_t size, ScsiPeripheral_DeviceMemMap **devMmap) Creates a buffer.
int32_t OH_ScsiPeripheral_DestroyDeviceMemMap(ScsiPeripheral_DeviceMemMap *devMmap) Destroys a buffer.
int32_t OH_ScsiPeripheral_ParseBasicSenseInfo(uint8_t *senseData, uint8_t senseDataLen, ScsiPeripheral_BasicSenseInfo *senseInfo) Parses basic sense data, including the Information, Command specific information, and Sense key specific fields.

For details about the interface, see SCSI Peripheral DDK.

How to Develop

The following describes how to use the SCSI Peripheral DDK to develop non-standard SCSI peripheral drivers.

Adding Dynamic Link Libraries

Add the following libraries to CMakeLists.txt.

libscsi.z.so

Including Header Files

#include <scsi_peripheral/scsi_peripheral_api.h>
#include <scsi_peripheral/scsi_peripheral_types.h>
  1. Initialize the SCSI Peripheral DDK.

    Use OH_ScsiPeripheral_Init in scsi_peripheral_api.h to initialize the SCSI Peripheral DDK.

    // Initialize the SCSI Peripheral DDK.
    int32_t ret = OH_ScsiPeripheral_Init();
    
  2. Open the device.

    After the SCSI Peripheral DDK is initialized, use OH_ScsiPeripheral_Open in scsi_peripheral_api.h to open the SCSI device.

    uint64_t deviceId = 0x100000003;
    uint8_t interfaceIndex = 0;
    ScsiPeripheral_Device *dev = NULL;
    // Open the SCSI device specified by deviceId and interfaceIndex1.
    ret = OH_ScsiPeripheral_Open(deviceId, interfaceIndex, &dev);
    
  3. Create a buffer.

    Use OH_ScsiPeripheral_CreateDeviceMemMap in scsi_peripheral_api.h to create the memory buffer devMmap.

    constexpr size_t DEVICE_MEM_MAP_SIZE = 1024;
    ScsiPeripheral_DeviceMemMap *g_scsiDeviceMemMap = nullptr;
    ret = OH_ScsiPeripheral_CreateDeviceMemMap(dev, DEVICE_MEM_MAP_SIZE, &g_scsiDeviceMemMap);
    
  4. Check whether the logical units are ready.

    Use OH_ScsiPeripheral_TestUnitReady in scsi_peripheral_api.h to check whether the logical unit is ready.

    ScsiPeripheral_TestUnitReadyRequest testUnitReadyRequest = {0};
    testUnitReadyRequest.timeout = 5000;
    ScsiPeripheral_Response testUnitReadyResponse = {0};
    ret = OH_ScsiPeripheral_TestUnitReady(dev, &testUnitReadyRequest, &testUnitReadyResponse);
    
  5. Query basic information about the SCSI device.

    Use OH_ScsiPeripheral_Inquiry in scsi_peripheral_api.h to obtain the basic information about the SCSI device.

    ScsiPeripheral_InquiryRequest inquiryRequest = {0};
    inquiryRequest.allocationLength = 512;
    inquiryRequest.timeout = 5000;
    ScsiPeripheral_InquiryInfo inquiryInfo = {0};
    inquiryInfo.data = g_scsiDeviceMemMap;
    ScsiPeripheral_Response inquiryResponse = {0};
    ret = OH_ScsiPeripheral_Inquiry(dev, &inquiryRequest, &inquiryInfo, &inquiryResponse);
    
  6. Obtain the capacity information about the SCSI device.

    Use OH_ScsiPeripheral_ReadCapacity10 in scsi_peripheral_api.h to obtain the SCSI device capacity information.

    ScsiPeripheral_ReadCapacityRequest readCapacityRequest = {0};
    readCapacityRequest.lbAddress = 0;
    readCapacityRequest.control = 0;
    readCapacityRequest.byte8 = 0;
    readCapacityRequest.timeout = 5000;
    ScsiPeripheral_CapacityInfo capacityInfo = {0};
    ScsiPeripheral_Response readCapacityResponse = {0};
    ret = OH_ScsiPeripheral_ReadCapacity10(dev, &readCapacityRequest, &capacityInfo, &readCapacityResponse);
    
  7. Obtain sense data.

    Use OH_ScsiPeripheral_RequestSense in scsi_peripheral_api.h to obtain sense data.

    ScsiPeripheral_RequestSenseRequest senseRequest = {0};
    senseRequest.allocationLength = SCSIPERIPHERAL_MAX_SENSE_DATA_LEN + 1;
    senseRequest.control = 0;
    senseRequest.byte1 = 0;
    senseRequest.timeout = 5000;
    ScsiPeripheral_Response senseResponse = {0};
    // Information returned by the SCSI device to the host, used to report the device status, error information, and diagnosis information.
    ret = OH_ScsiPeripheral_RequestSense(dev, &senseRequest, &senseResponse);
    
  8. Parse the sense data.

    Use OH_ScsiPeripheral_ParseBasicSenseInfo in scsi_peripheral_api.h to parse basic sense data, including the Information, Command specific information, and Sense key specific fields.

    ScsiPeripheral_BasicSenseInfo senseInfo = {0};
    ret = OH_ScsiPeripheral_ParseBasicSenseInfo(senseResponse.senseData, SCSIPERIPHERAL_MAX_SENSE_DATA_LEN, &senseInfo); 
    
  9. Read data.

    Use OH_ScsiPeripheral_Read10 in scsi_peripheral_api.h to read data from a specified logical block.

    ScsiPeripheral_IORequest readRequest = {0};
    readRequest.lbAddress = 1;
    readRequest.transferLength = 1;
    readRequest.control = 0;
    readRequest.byte1 = 0;
    readRequest.byte6 = 0;
    readRequest.timeout = 20000;
    readRequest.data = g_scsiDeviceMemMap;
    ScsiPeripheral_Response readResponse = {0};
    ret = OH_ScsiPeripheral_Read10(dev, &readRequest, &readResponse);
    
  10. Write data.

    Use OH_ScsiPeripheral_Write10 in scsi_peripheral_api.h to write data to a specified logical block of the device.

    ScsiPeripheral_IORequest writeRequest = {0};
    writeRequest.lbAddress = 1;
    writeRequest.transferLength = 1;
    writeRequest.control = 0;
    writeRequest.byte1 = 0;
    writeRequest.byte6 = 0;
    writeRequest.timeout = 5000;
    writeRequest.data = g_scsiDeviceMemMap;
    ScsiPeripheral_Response writeResponse = {0};
    ret = OH_ScsiPeripheral_Write10(dev, &writeRequest, &writeResponse);
    
  11. Verifies a specified logical block.

    Use OH_ScsiPeripheral_Verify10 in scsi_peripheral_api.h to verify a specified logical block.

    ScsiPeripheral_VerifyRequest verifyRequest = {0};
    verifyRequest.lbAddress = 1;
    verifyRequest.verificationLength = 1;
    verifyRequest.timeout = 5000;
    ScsiPeripheral_Response verifyResponse = {0};
    ret = OH_ScsiPeripheral_Verify10(dev, &verifyRequest, &verifyResponse);
    
  12. Send SCSI commands in CDB mode.

    Use OH_SCSIPeripheral_SendRequestByCdb in scsi_peripheral_api.h to send SCSI commands.

    ScsiPeripheral_Request sendRequest = {0};
    uint8_t cdbData[SCSIPERIPHERAL_MAX_CMD_DESC_BLOCK_LEN] = {0x28, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // The cstring header file needs to be imported.
    memcpy(sendRequest.commandDescriptorBlock, cdbData, SCSIPERIPHERAL_MAX_CMD_DESC_BLOCK_LEN);
    sendRequest.cdbLength = 10;
    sendRequest.dataTransferDirection = -3;
    sendRequest.timeout = 5000;
    sendRequest.data = g_scsiDeviceMemMap;
    ScsiPeripheral_Response sendResponse = {0};
    ret = OH_ScsiPeripheral_SendRequestByCdb(dev, &sendRequest, &sendResponse);
    
  13. Destroy the buffer.

    After all requests are processed and before the program exits, use OH_ScsiPeripheral_DestroyDeviceMemMap in scsi_peripheral_api.h to destroy the buffer.

    ret = OH_ScsiPeripheral_DestroyDeviceMemMap(g_scsiDeviceMemMap);
    
  14. Close the HID device.

    After the buffer is destroyed, use OH_ScsiPeripheral_Close in scsi_peripheral_api.h to close the device.

    // Stop the SCSI device.
    ret = OH_ScsiPeripheral_Close(&dev);
    
  15. Release the SCSI Peripheral DDK.

    After the SCSI device is closed, use OH_ScsiPeripheral_Release in scsi_peripheral_api.h to release the SCSI Peripheral DDK.

    // Release the SCSI Peripheral DDK.
    ret = OH_ScsiPeripheral_Release();
    

Debugging and Verification

Upon completion of driver application development, you can install the application on the OpenHarmony device. The test procedure is as follows:

  1. Click the driver application on the device. The application is started on the device.
  2. Check whether the application can read the basic information about the SCSI device.
  3. Select a SCSI command, enter parameters, and click the Send button.
  4. (Optional) Set the direction, CDB data, and CDB length, and click the Send button to run the corresponding SCSI command.

你可能感兴趣的鸿蒙文章

harmony 鸿蒙Driver Development Kit

harmony 鸿蒙Introduction to Driver Development Kit

harmony 鸿蒙UI-free Driver Development

harmony 鸿蒙Setting Up the Environment

harmony 鸿蒙FAQs

harmony 鸿蒙UI-based Driver Development

harmony 鸿蒙HID DDK Development

harmony 鸿蒙Terms

harmony 鸿蒙USB DDK Development

harmony 鸿蒙USB Serial DDK Development

0  赞