summaryrefslogtreecommitdiffstats
path: root/isys/pdc.c
blob: 6d5364040d2707a54ad2433653ebef0f409cc50c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/*
   pdc: Promise Fake Raid reader
	  Copyright (C) 2001

*/

#include <unistd.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <fcntl.h>
#include <linux/hdreg.h>

#ifdef DIET
#include <sys/mount.h>
#else
#include <linux/fs.h>
#endif

#include <string.h>


#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

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, &sectors))
	    return -1;
	
	if (ioctl(fd, BLKSSZGET, &sector_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 = -1;
	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);
	read (fd, buffer, bufsize);

	ret = 0;

	return ret;
}

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;
}