SES Page读写调用流程
1. SES Page概述
SES (SCSI Enclosure Services) Page是SAS Expander固件中用于管理和监控存储设备的重要机制。SES协议定义了多种Page类型,每种Page包含特定的状态信息或控制功能。常见的Page包括:
- Page 0x00: Supported Diagnostic Pages
- Page 0x01: Configuration Page
- Page 0x02: Enclosure Status/Control Page
- Page 0x03: Help Text Page
- Page 0x04: String In/Out Page
- Page 0x05: Threshold In/Out Page
- Page 0x07: Element Descriptor Page
- Page 0x0A: Device Element Page
- Page 0x0E: Microcode Page
- Page 0x0F: Nickname Page
- Page 0x82: Firmware Status Page (厂商自定义)
2. SES Page读取流程
SES Page的读取是通过SCSI RECEIVE DIAGNOSTIC RESULTS命令实现的。整体流程如下:
SCSI命令 -> STE模块 -> SES模块 -> DBS数据库
2.1 详细调用流程
-
SCSI命令接收
- 主机发送RECEIVE DIAGNOSTIC RESULTS命令
- 命令包含Page Code参数指定要读取的SES Page
-
STE模块处理
ste_rcv_diag_results()
解析SCSI命令- 调用
ste_ses_rcv_diag_results()
处理SES相关命令
-
SES模块处理
ses_rcv_diag_process()
根据Page Code分发到对应处理函数- 例如Page 0x01调用
ses_page_config_process()
-
数据库读取
ses_page_read()
从DBS数据库读取Page数据- 返回数据给主机
2.2 核心函数解析
PUBLIC BOOL ses_rcv_diag_process(UINT32 cmd_id,
scsi_initiator_id_type initiator,
UINT8 initiator_zone_tag,
UINT8 page_code,
UINT8 *page_ptr,
UINT16 buff_size,
UINT16 *page_size_ptr,
ses_sense_enum *sense_ptr)
{
/* 根据Page Code分发到不同的处理函数 */
switch(page_code)
{
case SES_PAGE_CODE_SUPP_DIAG_PG:
ses_page_supp_diag_process(page_size_ptr,
page_ptr,
buff_size,
sense_ptr);
break;
case SES_PAGE_CODE_CONFIG_PG:
ses_page_config_process(page_size_ptr,
page_ptr,
buff_size,
sense_ptr);
break;
/* 其他Page Code的处理... */
}
}
PUBLIC void ses_page_read(UINT16 dbs_page,
UINT16 *length_ptr,
UINT8 *buffer_ptr,
UINT16 buff_size,
BOOL *data_valid_ptr)
{
/* 读取SES Page长度 */
dbs_entry_read(dbs_page, PAGE_LENGTH_OFFSET,
sizeof(UINT16), temp_buffer);
/* 计算总长度 (Page长度 + 头部大小) */
*length_ptr = (UINT16)((temp_buffer[0]<<8) + (temp_buffer[1]) + 4);
/* 读取SES Page数据 */
dbs_entry_read(dbs_page, 0, *length_ptr, buffer_ptr);
/* 检查数据是否有效 */
dbs_page_data_valid_flag_check(dbs_page, data_valid_ptr);
}
3. SES Page写入流程
SES Page的写入是通过SCSI SEND DIAGNOSTIC命令实现的。整体流程如下:
SCSI命令 -> STE模块 -> SES模块 -> DBS数据库
3.1 详细调用流程
-
SCSI命令接收
- 主机发送SEND DIAGNOSTIC命令
- 命令包含Page Code和要写入的数据
-
STE模块处理
ste_send_diag()
解析SCSI命令- 调用
ste_ses_send_diag()
处理SES相关命令
-
SES模块处理
ses_send_diag_process()
解析Page头部- 根据Page Code分发到对应处理函数
- 例如Page 0x02调用
ses_page_encl_cntl_process()
-
数据库更新
- 更新DBS数据库中的Page数据
- 返回操作结果给主机
3.2 核心函数解析
PUBLIC BOOL ses_send_diag_process(UINT32 cmd_id,
scsi_initiator_id_type initiator,
UINT8 initiator_zone_tag,
UINT8 *diag_page_ptr,
UINT16 diag_page_len,
ses_sense_enum *sense_ptr)
{
/* 根据Page Code分发到不同的处理函数 */
switch(diag_page_ptr[0])
{
case SES_PAGE_CODE_ENCL_PG:
ses_page_encl_cntl_process(diag_page_len,
diag_page_ptr,
initiator,
initiator_zone_tag,
sense_ptr);
break;
case SES_PAGE_CODE_STR_PG:
ses_page_str_out_process(diag_page_len,
diag_page_ptr,
sense_ptr);
break;
/* 其他Page Code的处理... */
}
}
4. 主要SES Page处理函数
4.1 读取Page的处理函数
- ses_page_supp_diag_process(): 处理Supported Diagnostic Pages (Page 0x00)
- ses_page_config_process(): 处理Configuration Page (Page 0x01)
- ses_page_encl_stat_process(): 处理Enclosure Status Page (Page 0x02)
- ses_help_text_page_process(): 处理Help Text Page (Page 0x03)
- ses_page_str_in_process(): 处理String In Page (Page 0x04)
- ses_page_thr_in_process(): 处理Threshold In Page (Page 0x05)
- ses_page_element_desc_process(): 处理Element Descriptor Page (Page 0x07)
- ses_page_dev_element_process(): 处理Device Element Page (Page 0x0A)
- ses_microcode_status_page_process(): 处理Microcode Status Page (Page 0x0E)
- ses_nickname_status_page_process(): 处理Nickname Status Page (Page 0x0F)
4.2 写入Page的处理函数
- ses_page_encl_cntl_process(): 处理Enclosure Control Page (Page 0x02)
- ses_page_str_out_process(): 处理String Out Page (Page 0x04)
- ses_page_thr_out_process(): 处理Threshold Out Page (Page 0x05)
- ses_microcode_cntrl_page_process(): 处理Microcode Control Page (Page 0x0E)
- ses_nickname_control_page_process(): 处理Nickname Control Page (Page 0x0F)
5. 典型应用场景
5.1 读取设备状态
// 读取Enclosure Status Page获取设备状态
UINT8 buffer[1024];
UINT16 page_size;
ses_sense_enum sense;
BOOL result;
result = ses_rcv_diag_process(cmd_id,
initiator,
initiator_zone_tag,
SES_PAGE_CODE_ENCL_PG,
buffer,
sizeof(buffer),
&page_size,
&sense);
if (result && sense == SES_SENSE_NO_SENSE) {
// 解析buffer中的状态信息
ses_encl_header_struct *header = (ses_encl_header_struct *)buffer;
// 处理状态信息...
}
5.2 控制设备LED灯
// 构造Enclosure Control Page控制LED灯
UINT8 buffer[1024];
ses_sense_enum sense;
BOOL result;
// 填充Page头部
buffer[0] = SES_PAGE_CODE_ENCL_PG; // Page Code
buffer[1] = 0; // 保留字节
buffer[2] = 0; // Page Length高字节
buffer[3] = 24; // Page Length低字节
// 填充控制信息
// 例如:设置第一个磁盘槽位的LED为闪烁状态
buffer[8] = 0x80; // Select bit
buffer[9] = 0x02; // 闪烁状态
result = ses_send_diag_process(cmd_id,
initiator,
initiator_zone_tag,
buffer,
28, // 头部4字节 + 数据24字节
&sense);
5.3 固件版本信息读取
固件状态信息可以通过Page 0x82 (Firmware Status Page)获取:
// 读取Firmware Status Page获取固件版本信息
UINT8 buffer[1024];
UINT16 page_size;
ses_sense_enum sense;
BOOL result;
result = ses_rcv_diag_process(cmd_id,
initiator,
initiator_zone_tag,
SES_PAGE_CODE_FW_STAT_PG,
buffer,
sizeof(buffer),
&page_size,
&sense);
if (result && sense == SES_SENSE_NO_SENSE) {
// 解析buffer中的固件版本信息
ses_fw_status_page_struct *fw_status = (ses_fw_status_page_struct *)buffer;
UINT32 active_fw_revision = fw_status->active_fw_revision;
// 处理版本信息...
}
6. 注意事项
-
页面长度检查:调用
ses_page_length_check()
确保Page长度正确 -
生成码检查:调用
ses_page_gen_code_check()
验证生成码是否匹配 -
访问权限:某些Page的访问可能受到权限控制,需要验证initiator和zone_tag
-
数据库锁:操作DBS数据库时需要使用
dbs_page_lock()
和dbs_page_unlock()
-
错误处理:通过sense_ptr返回错误码,如SES_SENSE_INVALID_FIELD_IN_PARM_LIST
-
自定义Page:厂商可以实现自定义Page,如Firmware Status Page (0x82)