저 하늘의 구름처럼~

usb test result 본문

Embedded System

usb test result

강백호v 2009. 5. 18. 21:27
-  발생한 메시지 로그
 임베디드 보드 상에서 USB 허브를 이용하여 두개의 USB 간의 데이터 교환을 시도 하였으나 아래와
같은 메시지와 함께 데이터 교환이 정상적으로 이루어지지 않았다.

sd 2:0:0:0: rejecting I/O to offline device
sd 2:0:0:0: rejecting I/O to offline device
sd 2:0:0:0: rejecting I/O to offline device
sd 2:0:0:0: rejecting I/O to offline device
                                 .......
Buffer I/O error on device sdb1, logical block 3896
lost page write due to I/O error on sdb1

sd 2:0:0:0: rejecting I/O to offline device
Buffer I/O error on device sdb1, logical block 1982
lost page write due to I/O error on sdb1
Buffer I/O error on device sdb1, logical block 1983
lost page write due to I/O error on sdb1
                                 .......
sd 2:0:0:0: rejecting I/O to offline device
sd 2:0:0:0: rejecting I/O to offline device
sd 2:0:0:0: SCSI error: return code = 0x00010000
end_request: I/O error, dev sdb, sector 18311
usb 1-1.1: USB disconnect, address 5
usb 1-1.3: reset full speed USB device using s3c2410-ohci and address 3
usb 1-1.3: res0et full speed USB device using s3c2410-ohci and address 3
usb 1-1.1: new full speed USB device using s3c2410-ohci and address 6
usb 1-1.1: device descriptor read/64, error -110
usb 1-1.1: device descriptor read/64, error -110
usb 1-1.1: new full speed USB device using s3c2410-ohci and address 7
usb 1-1.1: device descriptor read/64, error -110

scsi 2:0:0:0 rejecting I/O to dead device
scsi 2:0:0:0 rejecting I/O to dead device
scsi 2:0:0:0 rejecting I/O to dead device 
                     ........


-  분석 결과

우선 USB 대용량 저장장치 책의 6장 SCSI 명령 131 page 부분에 보면 이러한 구문이 있습니다.

"SCSI 명령은 SCSI(Small Computer Systems Interface) 병렬 인터페이스를 사용하는 장치를 위해 개발 됐다. 이 명령은 저장장치의 정보를 알아내고, 장치의 동작을 제어하고, 저장 미디어로부터 데이터 블록을 읽고 쓸 수 있는 기반을 제공한다. USB를 포함한 다른 하드웨어 인터페이스들을 사용하는 저장장치들도 이러한 오퍼레이션들을 수행하기 위해 SCSI 명령을 사용한다."

라는 구문이 있었는데, 이것을 통해 USB 장치의 동작과 SCSI가 밀접한 관계가 있다는 것을 확인할 수 있었습니다. 실질적으로 커널 컴파일시에도 scsi 관련 옵션이 활성화 되어 있지 않다면 USB의 사용이 불가능합니다.

이러한 정보를 토대로, 커널 내부 소스를 몇몇 부분 분석을 해보았습니다. 분석해 본 결과 다음과 같은,

scsi 2:0:0:0 rejecting I/O to dead device

scsi 2:0:0:0 rejecting I/O to offline device 메시지는

drivers ->  scsi -> scsi_lib.c 에서 1178 줄에서 시작하는 함수에 의해 dead device & offline device 의 에러 처리가 이루어지고,

1458번째 줄에서  offline device 관련 에러 메시지가 처리된다는 것을 찾게 되었습니다.

우선 첫번째(1178줄의 함수  scsi_prep_fn)를 통해 추측해보면, 디바이스가 offline 상태,실행 상태가 아닌 경우, 디바이스가 완전하게 사라져 버린 경우 발생하는 것이라고 생각 되어지는데, usb 상의 데이터 교환시 usb 디바이스의 상태가 불안전하여 이러한 메시지 출력과 함께 데이터 전송이 잘되지 않을 수 있다고 생각합니다.

1178줄의 함수(scsi_request_fn)를 보면 I/O 요청이 호출 되었을 때 잠금 상태라고 판단되어지면 발생 된다고 하네요.. 

FAT : Directory bread(block 3900) failed 라는 메시지의 경우,

fs -> fat -> dir.c 의 함수 중 fat__get_entry 라는 함수를 살펴 보았습니다. 이 함수에서 핵심 부분으로

 if (*bh == NULL) {
     printk(KERN_ERR "FAT: Directory bread(block %llu) failed\n",
          (unsigned long long)phys);
   /* skip this block */

이러한 구문이 있었습니다. 소스를 보면 bh는 bufferhead라고 합니다. 이것이 null 값일 경우 전송하고자 하는 블럭을

스킵하고 다음 블록을 전송하고자 시도하는 형태로 구성되어 있었습니다.

 

간략히 요약하면, 문제가 발생되었던 이유가 USB 디바이스의 연결 상태가 외부적인 요인 혹은 내부적인 요인으로 인해 안정되지 못하여 데이터 전송이 잘 안 이루어지는 경우였을 거라고 생각되어지네요~ 최근에 다시 다른 USB 2개를 가지고 데이터 교환을 시도 하였을 때 3~4번연속으로 문제 없이 전송이 되었는데, 이것으로 보아 가장 큰 요인으로 usb 디바이스 연결 상태가 문제라고 생각되어 지네요 ^^

 

 -- 주요 함수들 원형 첨부 ---

static int scsi_prep_fn(struct request_queue *q, struct request *req)
{
       struct scsi_device *sdev = q->queuedata;
       int ret = BLKPREP_OK;

    /*
     * If the device is not in running state we will reject some
     * or all commands.( 만약 디바이스가 실행 상태가 아니라면, 우리는 몇개 혹은 모든 명령의 실행을 거부할 것이다.)
    */
   if (unlikely(sdev->sdev_state != SDEV_RUNNING)) {
      switch (sdev->sdev_state) {
       case SDEV_OFFLINE:
       /*
        * If the device is offline we refuse to process any
        * commands.  The device must be brought online
        * before trying any recovery commands. ( 만약 디바이스가 offline 상태이라면 우리는 어떤 명령들이라도 거부할 것이다.

          디바이스는 온라인 상태로 되기 전에 어떤 복구 명령들을 시도하여야 한다.)
       */
      sdev_printk(KERN_ERR, sdev,
        "rejecting I/O to offline device\n");
      ret = BLKPREP_KILL;
      break;
  case SDEV_DEL:
    /*
     * If the device is fully deleted, we refuse to
     * process any commands as well. ( 만약 디바이스가 완전히 없어진 상태라면, 우리는 어떤 명령들의 처리라도 거부할 것이다.
     */
   sdev_printk(KERN_ERR, sdev,
        "rejecting I/O to dead device\n");
   ret = BLKPREP_KILL;
   break;

 

             ..... (중략) ....

}

 

static int fat__get_entry(struct inode *dir, loff_t *pos,
     struct buffer_head **bh, struct msdos_dir_entry **de)
{
 struct super_block *sb = dir->i_sb;
 sector_t phys, iblock;
 unsigned long mapped_blocks;
 int err, offset;

next:

 

         ...... ( 중략 )  .....

if (*bh == NULL) {
  printk(KERN_ERR "FAT: Directory bread(block %llu) failed\n",
         (unsigned long long)phys);
  /* skip this block */
  *pos = (iblock + 1) << sb->s_blocksize_bits;
  goto next;
 }

    ...... ( 중략 )  .....

static void scsi_request_fn(struct request_queue *q) 함수 중 일부분.
 scsi의 경로 설정을 위한 주된 전략 ( Purpose : Main strategy routine for SCSI.)
 Lock status: IO request lock assumed to be held when called.
        ( 잠금 상태 : I0 요청이 호출 되었을 때 잠금 상태라고 추측되면 발생한다.?)

1458번째 줄
if (unlikely(!scsi_device_online(sdev))) {
   sdev_printk(KERN_ERR, sdev,"rejecting I/O to offline device\n");
   scsi_kill_request(req, q);
   continue;
}