1:由于工作的原因,在过去的几个月中,一直从事LSI公司的2*36port的expander方面的开发。其主要是对SAS中SSP,SMP,SES命令协议的解析及数据处理。

其LSI公司的SDK使用的是threadx操作系统,其芯片内核为ARM920t,在920t之提供了对SAS协议处理的功能。个人感觉代码风格不好。

现将个人对expander的理解整理如下:

The LSISAS2X36 is a 36-port, 6.0-Gbit/s Serial Attached SCSI (SAS) expander that enables the connection of up to 36 directly attached SAS or Serial ATA (SATA) devices, and provides table routing to support connections for up to 1024 SAS addresses. Each expander phy is individually configurable and performs SAS and SATA transfers based
on the speed of the host or target at either 6.0-Gbits/s, 3.0-Gbits/s, or 1.5-Gbits/s.expander在系统中角色处于"中间层"即向上连接initiator,向下连接target。上面描述可知:36port的expander可以直接连接36个tSAS或者SATA类型的target。expander 在进行性数据或者命令转发时,使用路由机制。基于每一个target的SAS地址进行数据包的路由。

所支持的协议:

A Serial SCSI Protocol (SSP)
B Serial ATA Tunneled Protocol (STP)
C Serial Management Protocol (SMP)
D SAS protocol, described in the Serial Attached SCSI (SAS) Standard, Revision 15a
E SATA, as defined in the Serial ATA: High Speed Serialized AT Attachment Specification,version 2.5
F SATA II

H SFF-8485 protocol, using the Serial GPIO (SGPIO) interface provided by theexpander

上面涉及到的协议SAS,SSP,STP,SMP可以参考一下章节:

SCSI Architecture Model - 5 (SAM-5)

SAS Protocol Layer (SPL)

SCSI Enclosure Services - 3 (SES-3)

SCSI Primary Commands - 4 (SPC-4)

SCSI Block Commands – 3 (SBC-3)  

SFF-8485 protocol 协议主要是控制GPIO的工作方式。

下面使用几张图来说明expander在整个存储系统的作用(不是我画的)

上图中可以看到,expander在系统中处于中间层,向上连接initiator,向下连接target。由于向下直接连接target,故图中的Routing types为D表示Direct。

上图主要使用多个expander来增加target的数量。

上图是路径冗余,主要是确保系统的可靠性,防止单点故障。

2:Linux下面的expander相关代码

而下面的代码是针对Marvell 公司提供的代码,其中SAS88SE9485/9445 6Gb/s SAS/SATA IO Controllers 为SAScontroller,其中expander的代码来自E:\src\linux-2.6.33.20\drivers\scsi\libsas这个目录中的SAS_expander.c。

现在看看linux下面的跟expander相关的代码,在linux之下跟SCSI,SAS相关的代码的目录如下:

E:\src\linux-2.6.33.20\drivers\scsi

E:\src\linux-2.6.33.20\include\scsi

其中

SAS_expander.c 的作用Serial Attached SCSI (SAS) Expander discovery and configuration

sas_init.c的作用 Serial Attached SCSI (SAS) Transport Layer initialization

文件mv_init.c

static int __init mvs_init(void)
{
 int rc;
 mvs_stt = sas_domain_attach_transport(&mvs_transport_ops);//函数的定义在:sas_init.c
 if (!mvs_stt)
  return -ENOMEM;

rc = pci_register_driver(&mvs_pci_driver);

if (rc)
  goto err_out;

return 0;

err_out:
 sas_release_transport(mvs_stt);
 return rc;
}

//函数的定义在:sas_init.c

struct scsi_transport_template *
sas_domain_attach_transport(struct sas_domain_function_template *dft)
{
 struct scsi_transport_template *stt = sas_attach_transport(&sft);//sft的定义在下面
 struct sas_internal *i;

if (!stt)
  return stt;

i = to_sas_internal(stt);
 i->dft = dft;
 stt->create_work_queue = 1;
 stt->eh_timed_out = sas_scsi_timed_out;
 stt->eh_strategy_handler = sas_scsi_recover_host;

return stt;
}

//函数指针的定义,主要用来获取expander或phy,enclosure的信息。

/* The functions by which the transport class and the driver communicate */
struct sas_function_template {
int (*get_linkerrors)(struct sas_phy *);
int (*get_enclosure_identifier)(struct sas_rphy *, u64 *);
int (*get_bay_identifier)(struct sas_rphy *);
int (*phy_reset)(struct sas_phy *, int);
int (*phy_enable)(struct sas_phy *, int);
int (*set_phy_speed)(struct sas_phy *, struct sas_phy_linkrates *);
int (*smp_handler)(struct Scsi_Host *, struct sas_rphy *, struct request *);
};

static struct sas_function_template sft = { //是对上面的结构体的初始化
.phy_enable = sas_phy_enable,
.phy_reset = sas_phy_reset,
.set_phy_speed = sas_set_phy_speed,
.get_linkerrors = sas_get_linkerrors,
.smp_handler = sas_smp_handler,
};

现在我们来看个简单的 .set_phy_speed = sas_set_phy_speed,

sas_set_phy_speed定义如下:

enum sas_linkrate {
 /* These Values are defined in the SAS standard */
 SAS_LINK_RATE_UNKNOWN = 0,
 SAS_PHY_DISABLED = 1,
 SAS_PHY_RESET_PROBLEM = 2,
 SAS_SATA_SPINUP_HOLD = 3,
 SAS_SATA_PORT_SELECTOR = 4,
 SAS_PHY_RESET_IN_PROGRESS = 5,
 SAS_LINK_RATE_1_5_GBPS = 8,
 SAS_LINK_RATE_G1 = SAS_LINK_RATE_1_5_GBPS,
 SAS_LINK_RATE_3_0_GBPS = 9,
 SAS_LINK_RATE_G2 = SAS_LINK_RATE_3_0_GBPS,
 SAS_LINK_RATE_6_0_GBPS = 10,
 /* These are virtual to the transport class and may never
  * be signalled normally since the standard defined field
  * is only 4 bits */
 SAS_LINK_RATE_FAILED = 0x10,
 SAS_PHY_VIRTUAL = 0x11,
};定义的为linkrate的 enumm。定义了SAS的链路速率。

int sas_set_phy_speed(struct sas_phy *phy,struct sas_phy_linkrates *rates)
{
 int ret;

//下面是判断SAS的速率是否正确

if ((rates->minimum_linkrate && rates->minimum_linkrate > phy->maximum_linkrate) ||
     (rates->maximum_linkrate && rates->maximum_linkrate < phy->minimum_linkrate))
  return -EINVAL;

if (rates->minimum_linkrate && rates->minimum_linkrate < phy->minimum_linkrate_hw)
  rates->minimum_linkrate = phy->minimum_linkrate_hw;

if (rates->maximum_linkrate && rates->maximum_linkrate > phy->maximum_linkrate_hw)
  rates->maximum_linkrate = phy->maximum_linkrate_hw;

if (scsi_is_sas_phy_local(phy)) { //根据scsi_is_sas_phy_local(phy)的值来判断使用哪个control函数来执行
  struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
  struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
  struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number];
  struct sas_internal *i =
   to_sas_internal(sas_ha->core.shost->transportt);

ret = i->dft->lldd_control_phy(asd_phy, PHY_FUNC_SET_LINK_RATE,rates);
 } else {
  struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent);
  struct domain_device *ddev = sas_find_dev_by_rphy(rphy);
  ret = sas_smp_phy_control(ddev, phy->number,
       PHY_FUNC_LINK_RESET, rates);

}

return ret;
}

i->dft->lldd_control_phy函数指针的赋值是在下面的结构体中进行的

static struct sas_domain_function_template mvs_transport_ops = {
 .lldd_dev_found  = mvs_dev_found,
 .lldd_dev_gone = mvs_dev_gone,

.lldd_execute_task = mvs_queue_command,
 .lldd_control_phy = mvs_phy_control,

.lldd_abort_task = mvs_abort_task,
 .lldd_abort_task_set    = mvs_abort_task_set,
 .lldd_clear_aca         = mvs_clear_aca,
       .lldd_clear_task_set    = mvs_clear_task_set,
 .lldd_I_T_nexus_reset = mvs_I_T_nexus_reset,
 .lldd_lu_reset   = mvs_lu_reset,
 .lldd_query_task = mvs_query_task,

.lldd_port_formed = mvs_port_formed,
 .lldd_port_deformed     = mvs_port_deformed,

};

mvs_phy_control,定义如下:

int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,void *funcdata)
{
int rc = 0, phy_id = sas_phy->id;
u32 tmp, i = 0, hi;
struct sas_ha_struct *sha = sas_phy->ha;
struct mvs_info *mvi = NULL;

while (sha->sas_phy[i]) {
if (sha->sas_phy[i] == sas_phy)
break;
i++;
}
hi = i/((struct mvs_prv_info *)sha->lldd_ha)->n_phy;
mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[hi];

switch (func) {
case PHY_FUNC_SET_LINK_RATE:
MVS_CHIP_DISP->phy_set_link_rate(mvi, phy_id, funcdata);
break;

case PHY_FUNC_HARD_RESET:
tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, phy_id);
if (tmp & PHY_RST_HARD)
break;
MVS_CHIP_DISP->phy_reset(mvi, phy_id, 1);
break;

case PHY_FUNC_LINK_RESET:
MVS_CHIP_DISP->phy_enable(mvi, phy_id);
MVS_CHIP_DISP->phy_reset(mvi, phy_id, 0);
break;

case PHY_FUNC_DISABLE:
MVS_CHIP_DISP->phy_disable(mvi, phy_id);
break;
case PHY_FUNC_RELEASE_SPINUP_HOLD:
default:
rc = -EOPNOTSUPP;
}
msleep(200);
return rc;
}上面的case语句,定义在SPL的9.4.3.28 PHY CONTROL function

Marvell 88SE9485/9445 6Gb/s SAS/SATA IO Controllers

const struct mvs_dispatch mvs_94xx_dispatch = { //定义了上面case中的函数。
 "mv94xx",
 mvs_94xx_init,
 NULL,
 mvs_94xx_ioremap,
 mvs_94xx_iounmap,
 mvs_94xx_isr,
 mvs_94xx_isr_status,
 mvs_94xx_interrupt_enable,
 mvs_94xx_interrupt_disable,
 mvs_read_phy_ctl,
 mvs_write_phy_ctl,
 mvs_read_port_cfg_data,
 mvs_write_port_cfg_data,
 mvs_write_port_cfg_addr,
 mvs_read_port_vsr_data,
 mvs_write_port_vsr_data,
 mvs_write_port_vsr_addr,
 mvs_read_port_irq_stat,
 mvs_write_port_irq_stat,
 mvs_read_port_irq_mask,
 mvs_write_port_irq_mask,
 mvs_get_sas_addr,
 mvs_94xx_command_active,
 mvs_94xx_issue_stop,
 mvs_start_delivery,
 mvs_rx_update,
 mvs_int_full,
 mvs_94xx_assign_reg_set,
 mvs_94xx_free_reg_set,
 mvs_get_prd_size,
 mvs_get_prd_count,
 mvs_94xx_make_prd,
 mvs_94xx_detect_porttype,
 mvs_94xx_oob_done,
 mvs_94xx_fix_phy_info,
 NULL,
 mvs_94xx_phy_set_link_rate,
 mvs_hw_max_link_rate,
 mvs_94xx_phy_disable,
 mvs_94xx_phy_enable,
 mvs_94xx_phy_reset,
 NULL,
 mvs_94xx_clear_active_cmds,
 mvs_94xx_spi_read_data,
 mvs_94xx_spi_write_data,
 mvs_94xx_spi_buildcmd,
 mvs_94xx_spi_issuecmd,
 mvs_94xx_spi_waitdataready,
#ifndef DISABLE_HOTPLUG_DMA_FIX
 mvs_94xx_fix_dma,
#endif
};

来个图更形象:

2:sas_init.c文件

在这个文件的最后可以看到有如下来个函数:

static int __init sas_class_init(void)
{
 sas_task_cache = kmem_cache_create("sas_task", sizeof(struct sas_task), 0, SLAB_HWCACHE_ALIGN, NULL); //如下有说明
 if (!sas_task_cache)
  return -ENOMEM;

return 0;
}

static void __exit sas_class_exit(void)
{
 kmem_cache_destroy(sas_task_cache);
}

在初始化函数和退出函数中,完成slab高速缓存的申请和释放。

在内核编程中,可能经常会有一些数据结构需要反复使用和释放,按照通常的思路,可能是使用kmalloc和kfree来实现。
但是这种方式效率不高,Linux为我们提供了更加高效的方法——Slab高速缓存管理器
通过先使用kmem_cache_create函数创建一个高速缓存的头指针——在内核中是struct kmem_cache结构,具体用法可以这样:struct kmem_cache * cachep = NULL ;

cachep = kmem_cache_create( "cache_name" , sizeof ( struct yourstruct) , 0, SLAB_HWCACHE_ALIGN, NULL , NULL ) ;

这样我们就获得了一个可用的cachep头指针。

SAS Expander及Linux下面的代码实现相关推荐

  1. 在linux上一行代码不用写实现自动采集+hadoop分词

    在linux上一行代码不用写实现自动采集+hadoop分词 将下面的shell脚本保存成到xxx.sh,然后执行即可 cd /opt/hadoop mkdir spider wget -O spide ...

  2. linux vim ctags,Linux环境上代码阅读与编写的利器-vim+ctags+cscope

    Linux环境下代码阅读与编写的利器----vim+ctags+cscope 所谓工欲善其事,必先利其器. 从事Linux程序开发,特别是Linux驱动程序的开发,不管是通过windows下虚拟一个L ...

  3. linux 定时器 代码,linux C++ 定时器代码

    linux C++ 定时器代码:#include #include #include using namespace std; /* union sigval { int sival_int; //i ...

  4. 苹果和linux_苹果发布ResearchKit,Linux采用冲突代码,等等

    苹果和linux 在本周的开放源代码新闻摘要中,我们来看看Apple的开放源代码ResearchKit,Linux内核社区采用了冲突代码等等! 2015年3月7日至13日的开源新闻摘要 苹果推出Res ...

  5. LXR( Linux超文本交叉代码检索工具)

    Linux超文本交叉代码检索工具LXR(Linux Cross Reference),是由挪威奥斯陆大学数学系Arne Georg Gleditsch和Per Kristian Gjermshus编写 ...

  6. GTK+实现linux聊天室代码详解-clientr端

    查看原代码请点击此超链接 注意!!此聊天室对红帽无兼容.需在其他linux系统上运行,如"深度". 加油学习! GTK+实现linux聊天室代码详解-server端:GTK+实现l ...

  7. 本机修改虚拟机linux中的代码文件

    最近在研究swoole这个框架,好不容易装了一个swoole,为了开发方面,需要早宿主机和虚拟机之间文件共享,一开始使用vmware tool可以实现共享,但是只能在linux中看到win共享的文件, ...

  8. linux svn checkout代码shell脚本

    linux svn checkout代码shell脚本 #!/bin/bash echo "欢迎上使用svn账户配置脚本" echo "当前版本V1.0.0" ...

  9. Linux vi 文本代码时显示行号或不显示行号

    Linux vi 文本代码时显示行号或不显示行号 前提  安装了vim $vi ~/.vimrc 显示的话加上 set nu 不想显示的话可以注释掉 "set nu 之后 $source ~ ...

最新文章

  1. 2007年下半年 网络工程师 上下午试卷【附带答案】
  2. 电脑能安装吗_安装暖气片有要求吗,装好的房子能安装吗?
  3. MariaDB/MySQL防止重复插入相同记录:INSERT IGNORE或者REPLACE
  4. 事务处理总结【JDBC事务|JTA事务|容器事务
  5. 构建器模式_我喜欢构建器模式的三个原因
  6. 在线编辑_水墨-在线 Markdown 编辑器
  7. int char转换成string java,java中int,char,string三种类型的相互转换
  8. 在windows下执行./configure,make,makeinstall源码安装程序spice-gtk
  9. 【数据结构(C语言)】数据结构-表
  10. sun的java认证考试_Sun Java认证考试科目
  11. 西南科技大学OJ题 利用二叉树中序及先序遍历确定该二叉树的后序序列0984
  12. LTE学习笔记二:扁平化的组网架构
  13. Multi-Task Feature Learning for Knowledge Graph Enhanced Recommendation
  14. react源码分析:babel如何解析jsx
  15. 【雪野实训记录】Oracle数据库 T4作业——事务和数据库对象
  16. Windows 筛选平台 (WFP)
  17. postgresql中替换字符串中的换行符和回车符号
  18. 基于混合高斯分布的EM算法提取声音特征并识别男女性别
  19. 学物生地对以后学计算机有影响吗,江苏高考改革后的第一届学生选考物生地,有什么问题吗?...
  20. css取消a标签自动换行,css中a元素放长英文字母或者数字自动换行的解决

热门文章

  1. element-ui 点击dialog右上角关闭图标不关闭的问题
  2. 我眼中的测试高手—测试架构师
  3. Win2K入侵检测实例分析
  4. MySQL获取当前时间、年月、年月日
  5. 【Minecraft开服】Windows搭建我的世界MC服务器「公网远程联机」
  6. CodeForces 360A - Levko and Array Recovery (模拟)
  7. 有效解决windows10系统 shift+右键 没有打开命令窗口选项的问题
  8. 【MineCraft】-- Mod制作物品与方块
  9. 网络机柜network cabinet
  10. Linux中搭建ftp服务器