Chinaunix首页 | 论坛 | 博客
  • 博客访问: 805891
  • 博文数量: 127
  • 博客积分: 2669
  • 博客等级: 少校
  • 技术积分: 1680
  • 用 户 组: 普通用户
  • 注册时间: 2009-10-23 11:39
文章分类

全部博文(127)

文章存档

2014年(5)

2013年(19)

2012年(25)

2011年(9)

2010年(25)

2009年(44)

分类: LINUX

2013-08-04 20:08:13

3.3 对于SCSI命令的模拟和处理

3.2小节中讲到scsi_debug中最主要的工作函数是scsi_debug_queuecommand_lck,该函数篇幅较长,以下对该函数的内容分部分进行解析。

static

int scsi_debug_queuecommand_lck(struct scsi_cmnd *SCpnt, done_funct_t done)

{

       

       if (target == SCpnt->device->host->hostt->this_id) {

              printk(KERN_INFO "scsi_debug: initiator's id used as "

                     "target!\n");

              return schedule_resp(SCpnt, NULL, done,

                                 DID_NO_CONNECT << 16, 0);

       }

       if ((SCpnt->device->lun >= scsi_debug_max_luns) &&

           (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))

              return schedule_resp(SCpnt, NULL, done,

                                 DID_NO_CONNECT << 16, 0);

       devip = devInfoReg(SCpnt->device);

       if (NULL == devip)

              return schedule_resp(SCpnt, NULL, done,

                                 DID_NO_CONNECT << 16, 0);

如果initiator idtarget id相同,或者scsi devicelun数目超出了允许的最大值,或者未找到相应的设备信息,则调用schedule_resp执行done回调函数并返回错误。

       if ((scsi_debug_every_nth != 0) &&

           (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {

              scsi_debug_cmnd_count = 0;

              if (scsi_debug_every_nth < -1)

                     scsi_debug_every_nth = -1;

              if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)

                     return 0; /* ignore command causing timeout */

              else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)

                     inj_recovered = 1; /* to reads and writes below */

              else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)

                     inj_transport = 1; /* to reads and writes below */

              else if (SCSI_DEBUG_OPT_DIF_ERR & scsi_debug_opts)

                     inj_dif = 1; /* to reads and writes below */

              else if (SCSI_DEBUG_OPT_DIX_ERR & scsi_debug_opts)

                     inj_dix = 1; /* to reads and writes below */

       }

接下来是scsi_debugfault injection机制,判断scsi_debug_every_nth并设置相应的injection标志位。

       if (devip->wlun) {

              switch (*cmd) {

              case INQUIRY:

              case REQUEST_SENSE:

              case TEST_UNIT_READY:

              case REPORT_LUNS:

                     break;  /* only allowable wlun commands */

              default:

                     if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)

                            printk(KERN_INFO "scsi_debug: Opcode: 0x%x "

                                   "not supported for wlun\n", *cmd);

                     mk_sense_buffer(devip, ILLEGAL_REQUEST,

                                   INVALID_OPCODE, 0);

                     errsts = check_condition_result;

                     return schedule_resp(SCpnt, devip, done, errsts,

                                        0);

              }

       }

此处检查wlun存在的情况下cmd是否合法,如果不合法则调用mk_sense_buffer构造sense buffer,之后返回。该函数定义如下:

static void mk_sense_buffer(struct sdebug_dev_info *devip, int key, int asc, int asq)

{

       unsigned char *sbuff;

       sbuff = devip->sense_buff;

       memset(sbuff, 0, SDEBUG_SENSE_LEN);

       scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);

       if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)

              printk(KERN_INFO "scsi_debug:    [sense_key,asc,ascq]: "

                    "[0x%x,0x%x,0x%x]\n", key, asc, asq);

}

调用了scsi_build_sense_buffer,该函数定义在drivers/scsi/scsi_error.c中,使用传入的ascascq构造出sense buffer,此处传入的ascascq分别为ILLEGAL_REQUESTINVALID_OPCODESense dataSCSI Primary Commands标准中定义为对于REQUEST SENSE,在返回CHECK CONDITION状态码下的参数数据。

switch (*cmd) {

       case INQUIRY:     /* mandatory, ignore unit attention */

              delay_override = 1;

              errsts = resp_inquiry(SCpnt, target, devip);

              break;

       case REQUEST_SENSE:      /* mandatory, ignore unit attention */

              delay_override = 1;

              errsts = resp_requests(SCpnt, devip);

              break;

       case REZERO_UNIT:    /* actually this is REWIND for SSC */

       case START_STOP:

              errsts = resp_start_stop(SCpnt, devip);

              break;

       

read:

              errsts = check_readiness(SCpnt, 0, devip);

              if (errsts)

                     break;

              if (scsi_debug_fake_rw)

                     break;

              get_data_transfer_info(cmd, &lba, &num, &ei_lba);

              errsts = resp_read(SCpnt, lba, num, devip, ei_lba);

              if (inj_recovered && (0 == errsts)) {

                     mk_sense_buffer(devip, RECOVERED_ERROR,

                                   THRESHOLD_EXCEEDED, 0);

                     errsts = check_condition_result;

              } else if (inj_transport && (0 == errsts)) {

                     mk_sense_buffer(devip, ABORTED_COMMAND,

                                   TRANSPORT_PROBLEM, ACK_NAK_TO);

                     errsts = check_condition_result;

              } else if (inj_dif && (0 == errsts)) {

                     mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);

                     errsts = illegal_condition_result;

              } else if (inj_dix && (0 == errsts)) {

write:

              errsts = check_readiness(SCpnt, 0, devip);

              if (errsts)

                     break;

              if (scsi_debug_fake_rw)

                     break;

              get_data_transfer_info(cmd, &lba, &num, &ei_lba);

              errsts = resp_write(SCpnt, lba, num, devip, ei_lba);

              if (inj_recovered && (0 == errsts)) {

                     mk_sense_buffer(devip, RECOVERED_ERROR,

                                   THRESHOLD_EXCEEDED, 0);

                     errsts = check_condition_result;

              } else if (inj_dif && (0 == errsts)) {

                     mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);

                     errsts = illegal_condition_result;

              } else if (inj_dix && (0 == errsts)) {

                     mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);

                     errsts = illegal_condition_result;

              }

              break;

       case WRITE_SAME_16:

       default:

              if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)

                     printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "

                            "supported\n", *cmd);

              errsts = check_readiness(SCpnt, 1, devip);

              if (errsts)

                     break;     /* Unit attention takes precedence */

              mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);

              errsts = check_condition_result;

              break;

       }

       return schedule_resp(SCpnt, devip, done, errsts,

                          (delay_override ? 0 : scsi_debug_delay));

}

可见,对于scsi command所有的处理都在此进行,此处选取INQUIRYWRITE(12)命令,参照spcsbc标准对其进行详细解释,其他命令字段读者可以参照SCSI相关标准,自行推导。

阅读(1632) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~