linux 下查看硬盘坏道代码(转)
2015-09-07 22:27
519 查看
对于硬盘的坏道的确没有什么好的办法,ata协议中的smart命令本意上是好的,但是很多的硬盘厂商并没有很好的实现smart的功能;硬盘的相关错误信息会存在相应的扇区里,但是这些扇区相当于一个环形的缓冲区,所以记录的错误信息有限,如果需要完整的硬盘坏道信息,smart就无能为力了。通过完整的读一遍硬盘可以找出坏道的完整信息,但是读牵涉到了DMA的数据传输过程所以效率较低;ata的协议里READ VERIFY (EXT)命令大大提高效率,该命令是NO DATA类型的;以下是具体的代码:
先摘来学习下
[cpp] view plaincopy #include <stdio.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #include <linux/hdreg.h> #include <linux/types.h> #include <sys/stat.h> #include <scsi/sg.h> #include <scsi/scsi.h> #include <sys/ioctl.h> #include <linux/fs.h> #include <fcntl.h> #include <errno.h> #include <sys/time.h> #define ATA_DRQ (1 << 3) /* data request i/o */ #define ATA_ERR (1 << 0) /* have an error */ #define DRIVER_SENSE 0x08 #define CONDITION_GOOD 0x02 #define ATA_PASS_THRU_12 12 #define ATA_12 0xa1 #define ATA_PASS_THRU_16 16 #define ATA_16 0x85 #define CMD_NO_DATA (3 << 1) #define FOR_SENSE_DATA 0x20 #define CMD_VERIFY_EXT 0x42 #define CMD_VERIFT 0x40 #define u64 unsigned long long #define u32 unsigned int #define u8 unsigned char struct ata_taskfile { u8 hob_feature; u8 hob_nsect; u8 hob_lbal; u8 hob_lbam; u8 hob_lbah; u8 feature; u8 nsect; u8 lbal; u8 lbam; u8 lbah; u8 device; u8 command; }; static u64 get_disk_size(const char *name) { const char *ptr = name + strlen(name) - 3; u64 size; char buff[128]; FILE *fp; sprintf(buff,"/sys/block/%s/size",ptr); if(NULL == (fp = fopen(buff,"r"))){ perror("fopen"); return 0; } fscanf(fp,"%lld",&size); fclose(fp); return size; } static void init_taskfile(struct ata_taskfile *tf,u64 lba,u32 nsect) { memset((void *)tf,0,sizeof(*tf)); tf->command = CMD_VERIFY_EXT; tf->device = 1 << 6; tf->lbal = lba; tf->lbam = lba >> 8; tf->lbah = lba >> 16; tf->nsect = nsect; tf->hob_nsect = nsect >> 8; tf->hob_lbal = lba >> 24; tf->hob_lbam = lba >> 32; tf->hob_lbah = lba >> 40; } static int sg_ioctl(int fd,struct ata_taskfile *tf) { u8 sense_buffer[32]; u8 cdb[ATA_PASS_THRU_16]; sg_io_hdr_t sg_io; int err = 0; memset(sense_buffer,0,32); memset((void *)&sg_io,0,sizeof(sg_io_hdr_t)); memset(cdb,0,ATA_PASS_THRU_16); cdb[0] = ATA_16; cdb[1] = CMD_NO_DATA; cdb[2] = FOR_SENSE_DATA; cdb[4] = tf->feature; cdb[6] = tf->nsect; cdb[8] = tf->lbal; cdb[10] = tf->lbam; cdb[12] = tf->lbah; cdb[13] = tf->device; cdb[14] = tf->command; cdb[1] |= 1; cdb[3] = tf->hob_feature; cdb[5] = tf->hob_nsect; cdb[7] = tf->hob_lbal; cdb[9] = tf->hob_lbam; cdb[11] = tf->hob_lbah; sg_io.cmd_len = ATA_PASS_THRU_16; sg_io.interface_id = 'S'; sg_io.cmdp = cdb; sg_io.mx_sb_len = sizeof(sense_buffer); sg_io.sbp = sense_buffer; sg_io.dxfer_direction = SG_DXFER_NONE; sg_io.timeout = 0; //sg default time 75s if((err = ioctl(fd,SG_IO,&sg_io)) == -1) { perror("SG_IO"); return err; } if(sg_io.host_status || DRIVER_SENSE != sg_io.driver_status || (sg_io.status && CONDITION_GOOD != sg_io.status)) { printf("SG_IO: bad response/n"); errno = EBADE; return -1; } if(0x72 != sense_buffer[0] || sense_buffer[7] < 14 || 0x09 != sense_buffer[8] || sense_buffer[9] < 0x0c) { printf("SG_IO:bad sense buffer 0x%x 0x%x 0x%x 0x%x/n", sense_buffer[0],sense_buffer[7],sense_buffer[8],sense_buffer[9]); errno = EBADE; return -1; } if(sense_buffer[21] & (ATA_DRQ | ATA_ERR)) { printf("I/O error, cmd = 0x%02x status = 0x%02x error = 0x%02x/n", tf->command, sense_buffer[21], sense_buffer[11]); errno = EIO; return -1; } return 0; } int ata_ioctl(int fd,u64 lba,u32 nsec) { unsigned char cdb[7]; int err = 0; cdb[0] = CMD_VERIFT; cdb[1] = 0x00; cdb[2] = nsec; cdb[3] = (lba >> 0) & 0xFF; cdb[4] = (lba >> 8) & 0xFF; cdb[5] = (lba >> 16) & 0xFF; cdb[6] = 0x40 | ((lba >> 24) & 0xFF); if (-1 == (err = ioctl(fd, HDIO_DRIVE_TASK, (void *)cdb))) { perror("HDIO_DRIVE_TASK"); return -1; } return 0; } int disk_verify_sectors(const char *name,int fd, u64 start, u32 size) { static u64 capacity = 0; struct ata_taskfile tf; if(0 == capacity){ capacity = get_disk_size(name); } init_taskfile(&tf,start,size); return sg_ioctl(fd,&tf); } int main(int argc, char *argv[]) { u64 offset = 0; int fd; u64 capacity; struct timeval t1,t2; int size; if (argc < 3) { printf("Usage: ./exec devname size/n"); printf("@devname:device name/n" "@size:per verifying sectors/n"); return 0; } capacity = get_disk_size(argv[1]); printf("disk capacity = %lld/n",capacity); size = atoi(argv[2]); printf("verfy disk granularity %d/n",size); if(-1 == (fd = open(argv[1],O_RDWR))){ perror("open"); return fd; } gettimeofday(&t1,NULL); while(1) { if((offset + size) > capacity){ size = offset - capacity; capacity = 0; } if (disk_verify_sectors(argv[1],fd,offset, size) < 0) { printf("%s:sectors between %Lu - %Lu error/n", argv[1],offset, offset+size); } offset += size; if(0 == capacity) break; } gettimeofday(&t2,NULL); printf("%s:verify over/n",argv[1]); printf("kill time = %ld s/n",(t2.tv_sec - t1.tv_sec)); close(fd); return 0; }转直http://blog.chinaunix.net/u3/101879/showart_2124196.html
相关文章推荐
- Centos使用光盘作为本地yum源
- Linux系统安装
- Linux find查找
- linux运维实战练习-2015年8月30日课程作业(2)
- Linux操作系统桌面环境GNOME和KDE的切换
- linux 管理参数调节
- Linux中brk()系统调用,sbrk(),mmap(),malloc(),calloc()的异同
- linux运维实战练习-2015年8月30日课程作业
- Linux在批量服务器管理中实用的PS1命令提示符格式实现方法
- Linux中的SSH登录
- Linux/Mac/Windows换行符及对'\r'和'\n'的不同处理
- 在linux 配置matlab的 libsvm
- 马哥linux学习(linux任务计划)
- Linux下配置用msmtp和mutt发邮件
- CentOS安装VMware Tools
- Linux下配置用msmtp和mutt发邮件
- linux或mac系统下的端口转发
- centos下安装mysql
- Linux-----Ubuntu搭建FTP服务器
- CentOS 加载/挂载光驱