/* pdc: Promise Fake Raid reader Copyright (C) 2001 */ #include #include #include #include #ifdef DIET #include #else #include #endif #include #ifdef DIET typedef char char16_t; typedef unsigned char u_int8_t; typedef unsigned short u_int16_t; typedef uint32_t u_int32_t; #else typedef unsigned int uint32_t; #endif #ifndef BLKSSZGET #define BLKSSZGET _IO(0x12,104)/* get block device sector size */ #endif #ifndef HDIO_GETGEO_BIG_RAW #define HDIO_GETGEO_BIG_RAW 0x0331 /* BIG GEOMETRY */ struct hd_big_geometry { unsigned char heads; unsigned char sectors; unsigned int cylinders; unsigned long start; }; #endif struct promise_raid_conf { char promise_id[24]; #define PR_MAGIC "Promise Technology, Inc." int32_t dummy_0; int32_t magic_0; int32_t dummy_1; int32_t magic_1; int16_t dummy_2; int8_t filler1[470]; struct { int32_t flags; /* 0x200 */ #define PR_F_CONFED 0x00000080 int8_t dummy_0; int8_t disk_number; int8_t channel; int8_t device; int32_t magic_0; int32_t dummy_1; int32_t dummy_2; /* 0x210 */ int32_t disk_secs; int32_t dummy_3; int16_t dummy_4; int8_t status; #define PR_S_DEFINED 0x01 #define PR_S_ONLINE 0x02 #define PR_S_OFFLINE 0x10 int8_t type; #define PR_T_STRIPE 0x00 #define PR_T_MIRROR 0x01 #define PR_T_STRIPE_MIRROR 0x04 #define PR_T_SPAN 0x08 u_int8_t total_disks; /* 0x220 */ u_int8_t raid0_shift; u_int8_t raid0_disks; u_int8_t array_number; u_int32_t total_secs; u_int16_t cylinders; u_int8_t heads; u_int8_t sectors; int32_t magic_1; int32_t dummy_5; /* 0x230 */ struct { int16_t dummy_0; int8_t channel; int8_t device; int32_t magic_0; int32_t disk_number; } disk[8]; } raid; int32_t filler2[346]; uint32_t checksum; }; static unsigned long long calc_pdcblock_offset (int fd) { unsigned long lba = 0; struct hd_big_geometry g; long sectors; int sector_size = 1; if (ioctl(fd, HDIO_GETGEO_BIG_RAW, &g)) return -1; if (ioctl(fd, BLKGETSIZE, §ors)) return -1; if (ioctl(fd, BLKSSZGET, §or_size)) return -1; if (!sector_size || !sectors || !g.cylinders || !g.heads || !g.sectors) return -1; sector_size /= 512; g.cylinders = (sectors / (g.heads * g.sectors)) / sector_size; lba = g.cylinders * (g.heads*g.sectors); lba = lba - g.sectors; return lba; } static int read_disk_sb (int fd, unsigned char *buffer,int bufsize) { int ret; unsigned long long sb_offset; /* * Calculate the position of the superblock, * it's at first sector of the last cylinder */ sb_offset = calc_pdcblock_offset(fd); if (sb_offset == ((unsigned long long) -1)) return -1; lseek64(fd, sb_offset * 512, SEEK_SET); ret = read (fd, buffer, bufsize); return 0; } static unsigned int calc_sb_csum (unsigned int* ptr) { unsigned int sum; int count; sum = 0; for (count=0;count<511;count++) sum += *ptr++; return sum; } int pdc_dev_running_raid(int fd) { struct promise_raid_conf *prom; unsigned char block[4096]; if (read_disk_sb(fd,(unsigned char*)&block,sizeof(block))) return -1; prom = (struct promise_raid_conf*)&block[0]; if (!strcmp(prom->promise_id, "Promise Technology, Inc.") && (prom->checksum == calc_sb_csum((unsigned int*)prom))) return 1; return 0; }